前言:
死锁问题,几乎可以用“自古”来形容。PV原语一出,信号量嵌套使用,就伴随着死锁问题的发生。死锁类问题的解决过程,基本上就是定位到发生死锁的位置以及原因,然后就是修正逻辑错误。这里重点说前者,就是用怎样的手段和方法,快速定位死锁位置和原因。题目中承诺的十分钟,也只是承诺这个过程。
分析:
1,准备条件
gdb :作者窃以为,Linux平台开发,必须会一手gdb。
debug symbol:编译的时候,带着-g选项;编译后,没有strip过。
2,发生了deadlock后,可以用两个办法:
a,gdb attach到目标进程上。
b,kill -6 pid,让进程coredump,使用coredump去分析(如果要使用coredump,需要确定/proc/pid/limits中的Max core file size是否满足大小要求,/proc/sys/kernel/core_pattern是否打开)。
3,开始分析
a,
以上述代码为例:编译生成测试程序deadlock并运行,只能看到两个线程分别enter func1&func2,没有leave。可知发生了deadlock。
b,作者使用了coredump的方式。并生成了deadlock.core。
启动gdb:gdb ./deadlock
加载coredump:core-file deadlock.core
查看线程:info threads,如下图
最后一帧是__lll_lock_wait的都可能是deadlock的发生点。
c,选择需要重点查看的线程:thread 8(如上图,线程8最后一帧停留在了__lll_lock_wait)
查看backtrace:bt
d,分析frame:frame 1(因为frame 1中调用了__GI___pthread_mutex_lock)
分析mutex1信息:p mutex1(因为__GI___pthread_mutex_lock的第一参数就是mutex1)
因为__owner = 3786,可知,mutex1的当前只有线程的tid就是3786.
e,结合代码继续分析当前线程的情况:frame 2
查看自己占用的mutex:p mutex2
因为__owner = 3787,可知,mutex2的当前只有线程的tid就是3787.
f,结合d和e两个步骤,可以知道:线程3787占用mutex2,并且请求mutex1.
g,再次使用c,d,e,f过程分析thread 13,同样可以得知:线程3786占用mutex1,并且请求mutex2.
h,结合f和g的分析结果,那么可以判断出来:当前进程的13个线程中,发生了deadlock的是线程3786和3787,并且线程3786占用mutex1,线程3787占用mutex2。问题分析到这里,作就算初步定位完了。剩下的工就是解决逻辑问题。
i,现在是两个线程卡在了__lll_lock_wait的地方,分析起来相对容易一些,如果是多个线程的最后一帧都是__lll_lock_wait函数,那么需要多花一些时间分析各个mutex的占用者和请求者。分析的过程中,也可以使用thread apply all bt这个命令,简单粗暴,打印出来所有线程的bt。
后记:
工具用的好,可以下班早。
多读LIBC,谁看都说好。