解锁多线程死锁之谜:深入探讨使用GDB调试的技巧( 二 )


解锁多线程死锁之谜:深入探讨使用GDB调试的技巧

文章插图
这里因为加了打印所以很快可以看到mutex2上锁那里卡住,实际环境会有很多线程运行,我们并不直到哪里会有问题 , 此时只能通过bt查看堆栈我们发现卡在函数__futex_abstimed_wait_common64,运行到./nptl/futex-internal.c文件第57行 。
这里我们只需要知道该函数__futex_abstimed_wait_common64是linux内核中用于处理互斥锁等待超时的一个内部函数即可 。
此时可以断定代码存在死锁问题了,我们继续排查 。
我们继续看bt信息,发现该等待是从#4  0x00005555555553c8 in main () at thread.c:59调入的,因为前面是#4,所以使用f 4进入该函数 。
解锁多线程死锁之谜:深入探讨使用GDB调试的技巧

文章插图
 
我们发现是main里调入,同时在执行thread1的pthread_join,所以前面的__futex_abstimed_wait_common64并不是我们真正要找的问题,其实thread1已经来到了join的位置 , 等待结束了 。我们继续执行thread Apply all bt把所有线程堆栈打出来看下:
解锁多线程死锁之谜:深入探讨使用GDB调试的技巧

文章插图
根据前面分析thread 1已经正常退出了,我们这里看到thread 2卡在futex_wait,根据上下文非常明显是在等待futex lock,再往下看我们发现锁mutex2,这里就是thread2在等待mutex2 , 那么mutex2被谁lock住没释放呢?我们通过p mutex2来查看owner即可知道该锁被谁拥有 。
解锁多线程死锁之谜:深入探讨使用GDB调试的技巧

文章插图
【解锁多线程死锁之谜:深入探讨使用GDB调试的技巧】这里有个问题,是因为该代码恰巧thread 1退出等待join了 , 所以这里的23890是个内核线程 , 在持有着mutex2,实际环境中我们会看到owner大概会是info threads中的LWP,于是就可以定位到该锁被谁持有没有释放了,再分析代码即可 。
我把thread 1再改下,不直接退出而是一直while(1)的形态来测试,此时再通过上述来查找mutex2被谁持有即可直观看到:
解锁多线程死锁之谜:深入探讨使用GDB调试的技巧

文章插图




推荐阅读