问题:
源程序来源于GItHub:recipes/Factory_deadlock.cc at master · chenshuo/recipes (github.com)
加了编译选项REPRODUCE_BUG
后会导致死锁,为什么会死锁呢?
个人分析:
这个程序一开始没有看懂,主要是几个知识点自己忽略了:
- 引用计数为0时,立刻调用定制的析构动作。
- 对象的析构是同步的,当最后一个指向
x
的shared_ptr
离开其作用域的时候,x
会同时在同一个线程析构。这个线程不一定是对象诞生的线程。
主要过程为:
- main线程创建了一个
Stock
对象叫MS
,该对象地址为0x56354caa90c0
- 由于该对象的引用计数为0,于是立即调用定制的析构函数
deleteStock
- 主线程在
deleteStock
中会休眠500毫秒,此时thrB
线程创建了一个Stock
对象也叫MS
,该对象地址为0x7f3020000b20
,这个对象覆盖了之前main线程创建的对象在哈希表中的位置。 - main线程从休眠中醒来,继续执行,发现此时指向
thrB
线程创建的Stock
对象的引用计数值为2。 - main线程再次休眠500毫秒。
-
thrB
线程执行结束,发现其创建的Stock
对象的引用计数值为1(在main线程中),所以该对象不会在thrB
中析构。 - main线程从休眠中唤醒,发现此时指向
thrB
线程创建的Stock
对象【0x7f3020000b20
】的引用计数值为1。离开作用域后,引用计数为0,这个对象要在main线程中被析构。 - main线程里面再次调用定制的析构函数
deleteStock
,于是导致死锁。
main: Stock[0x56354caa90c0] MS
main: stock 0x56354caa90c0
main: deleteStock[0x56354caa90c0]
thrB: Stock[0x7f3020000b20] MS
thrB: stockB 0x7f3020000b20
use_count = 2
thrB: stockB destructs
use_count = 1
main: deleteStock[0x7f3020000b20]
WARNING: mutex_ is already locked by this thread, deadlock will happen.
如果没有互斥锁的话,结果会这样:
main: Stock[0x55c6ae0d40c0] MS
main: stock 0x55c6ae0d40c0
main: deleteStock[0x55c6ae0d40c0]
thrB: Stock[0x7fa980000b20] MS
thrB: stockB 0x7fa980000b20
use_count = 2
thrB: stockB destructs
use_count = 1
main: deleteStock[0x7fa980000b20]
main: ~Stock[0x7fa980000b20] MS
main: ~Stock[0x55c6ae0d40c0] MS
main :~Thread