死锁(deallocks):是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程(线程)在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
一种交叉持锁死锁的情形,此时执行程序中两个或多个线程发生永久堵塞(等待),每个线程都在等待被其它线程占用并堵塞了的资源。例如,如果线程1锁住了记录A并等待记录B,而线程2锁住了记录B并等待记录A,这样两个线程就发生了死锁现象。在计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。
产生死锁的四个必要条件
(1)互斥条件:一个资源每次只能被一个进程(线程)使用。
(2)请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。
(3)不剥夺条件:此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。
(4)循环等待条件:多个进程(线程)之间形成一种头尾相接的循环等待资源关系。
图1.交叉持锁的死锁示意图:
注释:在执行func2和func4之后,子线程1获得了锁A,正试图获得锁B,但是子线程2此时获得了锁B,正试图获得锁A,所以子线程1和子线程2将没有办法得到锁A和锁B,因为它们各自被对方占有,永远不会释放,所以发生了死锁的现象。
使用pstack和gdb工具对死锁程序进行分析
pstack在Linux平台上的简单介绍
pstack是Linux(比如RedHatLinux系统、UbuntuLinux系统等)下一个很有用的工具,它的功能是打印输出此进程的堆栈信息。可以输出所有线程的调用关系栈。
gdb在Linux平台上的简单介绍
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。Linux系统中包含了GNU调试程序gdb,它是一个用来调试C和C++程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况.
gdb所提供的一些主要功能如下所示:
1运行程序,设置能影响程序运行的参数和环境;
2控制程序在指定的条件下停止运行;
3当程序停止时,可以检查程序的状态;
4当程序crash时,可以检查core文件;
5可以修改程序的错误,并重新运行程序;
6可以动态监视程序中变量的值;
7可以单步执行代码,观察程序的运行状态。
gdb程序调试的对象是可执行文件或者进程,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用gdb调试。如果要让产生的可执行文件可以用来调试,需在执行g++(gcc)指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb利用这些信息使源代码和机器码相关联。gdb的基本命令较多,不做详细介绍,大家如果需要进一步了解,请参见gdb手册。
清单1.测试程序
#include#include#includepthread_mutex_tmutex1=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_tmutex2=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_tmutex3=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_tmutex4=PTHREAD_MUTEX_INITIALIZER;staticintsequence1=0;staticintsequence2=0;intfunc1(){pthread_mutex_lock(&mutex1);++sequence1;sleep(1);pthread_mutex_lock(&mutex2);++sequence2;pthread_mutex_unlock(&mutex2);pthread_mutex_unlock(&mutex1);returnsequence1;}intfunc2(){pthread_mutex_lock(&mutex2);++sequence2;sleep(1);pthread_mutex_lock(&mutex1);++sequence1;pthread_mutex_unlock(&mutex1);pthread_mutex_unlock(&mutex2);returnsequence2;}void*thread1(void*arg){while(1){intiRetValue=func1();if(iRetValue==100000){pthread_exit(NULL);}}}void*thread2(void*arg){while(1){intiRetValue=func2();if(iRetValue==100000){pthread_exit(NULL);}}}void*thread3(void*arg){while(1){sleep(1);charszBuf[128];memset(szBuf,0,sizeof(szBuf));strcpy(szBuf,"thread3");}}void*thread4(void*arg){while(1){sleep(1);charszBuf[128];memset(szBuf,0,sizeof(szBuf));strcpy(szBuf,"thread3");}}intmain(){pthread_ttid[4];if(pthread_create(&tid[0],NULL,&thread1,NULL)!=0){_exit(1);}if(pthread_create(&tid[1],NULL,&thread2,NULL)!=0){_exit(1);}if(pthread_create(&tid[2],NULL,&thread3,NULL)!=0){_exit(1);}if(pthread_create(&tid[3],NULL,&thread4,NULL)!=0){_exit(1);}sleep(5);//pthread_cancel(tid[0]);pthread_join(tid[0],NULL);pthread_join(tid[1],NULL);pthread_join(tid[2],NULL);pthread_join(tid[3],NULL);pthread_mutex_destroy(&mutex1);pthread_mutex_destroy(&mutex2);pthread_mutex_destroy(&mutex3);pthread_mutex_destroy(&mutex4);return0;}