問題:
源程序來源于GItHub:recipes/Factory_deadlock.cc at master · chenshuo/recipes (github.com)
加了編譯選項(xiàng)REPRODUCE_BUG
后會(huì)導(dǎo)致死鎖忿危,為什么會(huì)死鎖呢诫舅?
個(gè)人分析:
這個(gè)程序一開始沒有看懂,主要是幾個(gè)知識(shí)點(diǎn)自己忽略了:
- 引用計(jì)數(shù)為0時(shí)锭部,立刻調(diào)用定制的析構(gòu)動(dòng)作攒发。
- 對(duì)象的析構(gòu)是同步的驳癌,當(dāng)最后一個(gè)指向
x
的shared_ptr
離開其作用域的時(shí)候娄琉,x
會(huì)同時(shí)在同一個(gè)線程析構(gòu)融击。這個(gè)線程不一定是對(duì)象誕生的線程筑公。
主要過程為:
- main線程創(chuàng)建了一個(gè)
Stock
對(duì)象叫MS
,該對(duì)象地址為0x56354caa90c0
- 由于該對(duì)象的引用計(jì)數(shù)為0尊浪,于是立即調(diào)用定制的析構(gòu)函數(shù)
deleteStock
- 主線程在
deleteStock
中會(huì)休眠500毫秒匣屡,此時(shí)thrB
線程創(chuàng)建了一個(gè)Stock
對(duì)象也叫MS
,該對(duì)象地址為0x7f3020000b20
拇涤,這個(gè)對(duì)象覆蓋了之前main線程創(chuàng)建的對(duì)象在哈希表中的位置捣作。 - main線程從休眠中醒來,繼續(xù)執(zhí)行鹅士,發(fā)現(xiàn)此時(shí)指向
thrB
線程創(chuàng)建的Stock
對(duì)象的引用計(jì)數(shù)值為2券躁。 - main線程再次休眠500毫秒。
-
thrB
線程執(zhí)行結(jié)束掉盅,發(fā)現(xiàn)其創(chuàng)建的Stock
對(duì)象的引用計(jì)數(shù)值為1(在main線程中)也拜,所以該對(duì)象不會(huì)在thrB
中析構(gòu)。 - main線程從休眠中喚醒趾痘,發(fā)現(xiàn)此時(shí)指向
thrB
線程創(chuàng)建的Stock
對(duì)象【0x7f3020000b20
】的引用計(jì)數(shù)值為1慢哈。離開作用域后,引用計(jì)數(shù)為0永票,這個(gè)對(duì)象要在main線程中被析構(gòu)卵贱。 - main線程里面再次調(diào)用定制的析構(gòu)函數(shù)
deleteStock
滥沫,于是導(dǎo)致死鎖。
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.
如果沒有互斥鎖的話艰赞,結(jié)果會(huì)這樣:
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