死锁问题调试-思路分析
2015-09-09 20:18
260 查看
今儿晚上碰到一死锁问题,之前定位没定位出来,讨论问题时被人指出来了,感觉很羞愧。
记录下,下次碰到类似死锁要有思路。
咱们死锁一般有两种情况,
1.线程A和线程B相互死锁。这种情况下,通过堆栈查找两个等待锁之间的依赖关系,还是比较好确定的。
2.线程A自死锁,造成这种死锁的情况是自己加了锁之后,还没来得及释放,下次又继续等锁,而这种锁刚好又不是递归锁,就会出现自死锁的情况。
针对于情况一:
一般思路,还是用gdb观察当前线程快照,如果现在功能卡住,而且gdb几次快照都在某个预期很快获取到锁的地方等锁,那么基本能确定是死锁。 那么,第二步就应该是获取该锁的ownerID,看这把锁到底是被哪个线程持有。ok,问题来了,如果这个时候gdb看不到ownerID,原因有很多(比如给你的就只有一个gdb快照,但是已经被定位为死锁,现场已经被破坏了,而且很难复现)怎么办?那么只好根据堆栈来查代码了,看上一层堆栈进入时,有进入什么锁。。。一层一层查,看能否能查到和另外那个互死锁的锁进锁的地方。好吧,我承认这个方法很low。
针对情况二:
猜想的原因有两种,一种是自己这段代码中在加锁后真的就没有完成锁释放,而且下次还能继续执行到加锁进入的代码入口。第二种,是锁的加锁和释放锁确实成对了,但是在加锁后,有可能被中断,而中断执行的中断函数(或者信号函数)也有这边锁的进入,就会造成自死锁。
很不幸,我今儿碰到的是第二种。而且只看到了堆栈,没法用gdb查看堆栈内变量的值,现场也已经被破坏掉了。从堆栈上和代码相结合我们看到了线程确实死锁了,因为锁不应该在这个地方长时间等待。
两个线程在等同一把锁,但是奇怪的是从代码上直接看,是看不到有其他线程能够持有这把锁的。所以一直被他们说持有这把锁的线程消失了。由于没有能复现,也没法查看占用锁的线程,所以当时就放过了这个问题。今儿开会过问题,被翻出来看了,结果被其他同事指出来了。
最关键的地方是:先看下死锁线程的更底层堆栈,看这些堆栈有进什么锁,或者什么操作会影响到锁。
这个问题的是,
frame 0:在信号处理函数中等待这把锁mutexM
frame1:进入这个信号处理函数B
gdb中提示<signal handler called>
frame2:write
frame3:函数A
按照刚才的思路,我们查看frame2,发现write接口之前即在函数A中是有进这把锁mutexM的,只是在宏里面被隐藏了。然后调用了write,在write时,信号中断了,调用了信号处理函数,这个函数中又要求进mutexM,然而此时函数A还未执行到mutexM的leave操作,因此出现了死锁。
另一个线程又刚好也在等这把锁,因此从堆栈上直接看上去,有两个线程都在等这把锁,但是没看到占有锁的线程。
记录下,下次碰到类似死锁要有思路。
咱们死锁一般有两种情况,
1.线程A和线程B相互死锁。这种情况下,通过堆栈查找两个等待锁之间的依赖关系,还是比较好确定的。
2.线程A自死锁,造成这种死锁的情况是自己加了锁之后,还没来得及释放,下次又继续等锁,而这种锁刚好又不是递归锁,就会出现自死锁的情况。
针对于情况一:
一般思路,还是用gdb观察当前线程快照,如果现在功能卡住,而且gdb几次快照都在某个预期很快获取到锁的地方等锁,那么基本能确定是死锁。 那么,第二步就应该是获取该锁的ownerID,看这把锁到底是被哪个线程持有。ok,问题来了,如果这个时候gdb看不到ownerID,原因有很多(比如给你的就只有一个gdb快照,但是已经被定位为死锁,现场已经被破坏了,而且很难复现)怎么办?那么只好根据堆栈来查代码了,看上一层堆栈进入时,有进入什么锁。。。一层一层查,看能否能查到和另外那个互死锁的锁进锁的地方。好吧,我承认这个方法很low。
针对情况二:
猜想的原因有两种,一种是自己这段代码中在加锁后真的就没有完成锁释放,而且下次还能继续执行到加锁进入的代码入口。第二种,是锁的加锁和释放锁确实成对了,但是在加锁后,有可能被中断,而中断执行的中断函数(或者信号函数)也有这边锁的进入,就会造成自死锁。
很不幸,我今儿碰到的是第二种。而且只看到了堆栈,没法用gdb查看堆栈内变量的值,现场也已经被破坏掉了。从堆栈上和代码相结合我们看到了线程确实死锁了,因为锁不应该在这个地方长时间等待。
两个线程在等同一把锁,但是奇怪的是从代码上直接看,是看不到有其他线程能够持有这把锁的。所以一直被他们说持有这把锁的线程消失了。由于没有能复现,也没法查看占用锁的线程,所以当时就放过了这个问题。今儿开会过问题,被翻出来看了,结果被其他同事指出来了。
最关键的地方是:先看下死锁线程的更底层堆栈,看这些堆栈有进什么锁,或者什么操作会影响到锁。
这个问题的是,
frame 0:在信号处理函数中等待这把锁mutexM
frame1:进入这个信号处理函数B
gdb中提示<signal handler called>
frame2:write
frame3:函数A
按照刚才的思路,我们查看frame2,发现write接口之前即在函数A中是有进这把锁mutexM的,只是在宏里面被隐藏了。然后调用了write,在write时,信号中断了,调用了信号处理函数,这个函数中又要求进mutexM,然而此时函数A还未执行到mutexM的leave操作,因此出现了死锁。
另一个线程又刚好也在等这把锁,因此从堆栈上直接看上去,有两个线程都在等这把锁,但是没看到占有锁的线程。
相关文章推荐
- 将字符串按倒序进行排序 Collections.reverseOrder()
- zkw费用流模板(适用二分图)
- 播放多媒体文件的类——Mediaplayer
- Redis系列-存储篇list主要操作函数小结(转)
- unity之Post,Get请求
- 继承多态详解
- xml文档的两种解析方式
- hdu 2018 母牛的故事
- CC2540开发入门
- PHP中的面向对象
- 欢迎使用CSDN-markdown编辑器
- poj 1753 Flip Game【dfs】
- Word 2007 如何设置正文第一页----目录显示正文从第一页开始
- linux /sbin FHS翻译
- shell脚本操作mysql数据库 (部份参考)
- hdu 1285
- 88 thinkphp 有模型没有表
- 一个文件夹遍历工具
- Android多线程、Handler和AsyncTask的用法
- MySQL Workbench中如何开启MySQL的远程帐号