如休防止出现死锁:
构成死锁的四个条件只有一个不成立,就不会产生死锁了。
1、破坏互斥条件,让资源能够共享使用(准备多份)。
2、破坏占有且等待的条件,一次申请完成它所有需要的资源(把所有资源进行打包,用一把锁来代表,拿到这反锁就相当于拿到的所有资源),资源没有满足前不让它运行,一旦开始运行就一直归它所有, 缺点是系统资源会被浪费。
3、破坏不可剥夺的条件,当已经占有了一些资源,请求新的资源而获取不到,然后就释放已经获取到的资源,缺点是实现起来比较复杂,释放已经获取到的资源可能会造成前一阶段的工作浪费。
4、破坏循环等待的条件,采用顺序分配资源的方法,在系统中为资源进行编号,规定线程必须按照编号递增的顺序获取资源,缺点是资源必须相对稳定,这样就限制了资源的增加和减少。
#include <stdio.h> #include <unistd.h> #include <pthread.h> // 创建三个互斥锁并初始化 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; void* run1(void* arg) { while(1) { pthread_mutex_lock(&mutex1); usleep(100); if(0 == pthread_mutex_trylock(&mutex2)) break; pthread_mutex_unlock(&mutex1); } printf("没有构成死锁!!!\n"); pthread_mutex_unlock(&mutex2); pthread_mutex_unlock(&mutex1); } void* run2(void* arg) { while(1) { pthread_mutex_lock(&mutex2); usleep(100); if(0 == pthread_mutex_trylock(&mutex3)) break; pthread_mutex_unlock(&mutex2); } printf("没有构成死锁!!!\n"); pthread_mutex_unlock(&mutex3); pthread_mutex_unlock(&mutex2); } void* run3(void* arg) { while(1) { pthread_mutex_lock(&mutex3); usleep(100); if(0 == pthread_mutex_trylock(&mutex1)) break; pthread_mutex_unlock(&mutex3); } printf("没有构成死锁!!!\n"); pthread_mutex_unlock(&mutex1); pthread_mutex_unlock(&mutex3); } int main(int argc,const char* argv[]) { // 创建三个线程 pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,run1,NULL); pthread_create(&tid2,NULL,run2,NULL); pthread_create(&tid3,NULL,run3,NULL); // 主线程等待三个子线程结束 pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); return 0; }
检测死锁的方法:
总体思路:观察+分析
方法1:阅读代码,分析各线程的加锁步骤。
方法2:使用strace追踪程序的执行流程。
方法3:查看日志观察程序的业务执行过程。
方法4:使用gdb调试,查看各线程的执行情况。
1、把断点打在线程创建完毕后 2、run 3、info threads 查看所有线程 4、thread n 进程指定的线程 5、bt 查看线程堆栈信息 6、配合s/n单步调试