thread apply all bt(back trace)每一个线程都在查看调用栈
死锁使用的两种场景
1.1 不解锁
1.2 吃着碗里的看着锅里的
锁1加锁于线程1、锁2加锁于线程2。此时线程1继续请求加锁锁2、亦或者线程2继续请求加锁锁1,都会造成死锁。(挖墙脚是一种不礼貌、不道德的行为)
死锁模拟场景
2.1 不解锁情况模拟:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void* mythread_strat(void* arg)
{
int count=10;
while(1){
pthread_mutex_lock(&mutex);
if(count<0){
break;
}
count--;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
for(int i=0;i<2;i++)
{
pthread_t tid;
int ret=pthread_create(&tid,NULL,mythread_strat,NULL);
if (ret<0){
perror("pthreat_create");
return 0;
}
}
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);
printf("mutex...\n");
while(1)
{
sleep(1);
}
return 0;
}
结果运行情况:
mutex...
结果表示死锁模拟成功。
2.2 吃着碗里看着锅里的情况:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
void* mythread_stratA(void* arg){
pthread_mutex_lock(&mutex1);
sleep(1); //让线程B将2锁拿走
pthread_mutex_lock(&mutex2);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}
void* mythread_stratB(void* arg){
pthread_mutex_lock(&mutex2);
sleep(1); //让线程A将1锁拿走
pthread_mutex_lock(&mutex1);
pthread_mutex_unlock(&mutex1);
pthread_mutex_unlock(&mutex2);
}
int main(){
pthread_mutex_init(&mutex1, NULL);
pthread_mutex_init(&mutex2, NULL);
pthread_t tid;
int ret = pthread_create(&tid, NULL, mythread_stratA, NULL);
if(ret < 0){
perror("pthread_create");
return 0;
}
ret = pthread_create(&tid, NULL, mythread_stratB, NULL);
if(ret < 0){
perror("pthread_create");
return 0;
}
while(1){
sleep(1);
}
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
死锁的gdb分析
进入gdb调试
(gdb)t 3 //切换到3号线程
(gdb)bt
(gdb)f 3 //查看请求的锁
(gdb)p mutex2 //查看2锁
2锁信息:__owner=23778 //表示本锁被线程23778调走
若线程3想要请求2锁,必须解决23778线程。
死锁的必要条件
4.1 不可剥夺:线程获取到互斥锁之后,除了自己释放,其他线程不能进行释放。
4.2 循环等待:线程A拿着锁1,请求锁2,同时线程B拿着锁2,请求锁1
4.3 互斥条件:一个互斥锁,在同一时间内只能被一个线程所拥有
4.4 请求与保持:吃着碗里的看着锅里的
四个条件当中不可剥夺和互斥条件时互斥锁的技术属性,程序员无法通过更改代码使其改变;
程序员可以通过改变代码的手段破坏循环等待或者请求与保持条件。
代码怎么预防死锁
5.1 破坏必要条件:循环等待/请求与保持
5.2 枷锁顺序一致:都先加锁1、再加锁2
5.3 避免锁没有被释放:在所有可能线程退出的地方进行解锁
5.4 资源一次性分配:多个资源在代码当中有可能每一个资源都需要使用不同的锁进行保护