多執行緒死鎖除錯小技巧
據說再高的高手在寫多執行緒程式的時候都難確保不會產生死鎖,死鎖的除錯也就成為一個比較常見的問題,假設有下面這樣一個問題:
一個正在生產環境下執行的程式死鎖了,或者你只是在跑一個程式,並沒有在偵錯程式裡面開啟它,然後發現沒有響應,日誌輸出也停止了。由於你是一個有經驗的程式設計師,會想到“我剛剛加上了新的鎖策略,不一定穩定,這可能是死鎖了“。但是你不想就這麼殺掉程式,因為多執行緒的 bug 不容易重現,遇上一次死鎖可能要憑運氣,錯過了這次,它下次死鎖可能會出現在你演示給老闆看的時候……怎麼辦?
對於這樣的問題可以藉助Core Dump來除錯。
什麼是Core Dump?
Core的意思是記憶體, Dump的意思是扔出來, 堆出來.開發和使用Unix程式時, 有時程式莫名其妙的down了, 卻沒有任何的提示(有時候會提示core dumped). 這時候可以檢視一下有沒有形如core.程式號的檔案生成執行過程中發生異常, 程式異常退出時, 由作業系統把程式當前的記憶體狀況儲存在一個core檔案中, 叫core dump.這個檔案便是作業系統把程式down掉時的記憶體內容扔出來生成的, 它可以做為除錯程式的參考.
Core Dump又叫核心轉儲, 當程式沒有core檔案生成怎麼辦呢?
有時候程式down了, 但是core檔案卻沒有生成,core檔案的生成跟你當前系統的環境設定有關係, 可以用下面的語句設定一下, 然後再執行程式便會生成core檔案.
ulimit -c unlimited
core檔案生成的位置一般於執行程式的路徑相同, 檔名一般為core.程式號,在我的ubuntu12.04lts下生產的檔名為core。
介紹了core dump之後,來看看如何在多執行緒除錯中使用core dump。
使用 kill 命令產生 core dump檔案:
kill -11 pid
這不還是殺掉程式嘛?沒錯,但是你用訊號11殺掉它,會讓程式產生一個 Segmentation Fault,從而(如果你沒禁用 core dump 的話),導致一個 core dump。隨後你得到一個 core 檔案,裡面包含了死鎖的時候,程式的記憶體映象,也就包括了正在糾結纏綿,生離死別從而產生死鎖的那兩個,沒準是幾個,執行緒們的,棧。
現在知道該怎麼辦了吧?用 gdb 開啟這個 core 檔案,然後
thread apply all bt
gdb 會打出所有執行緒的棧,如果你發現有那麼幾個棧停在 pthread_wait 或者類似呼叫上,大致就可以得出結論:就是它們幾個兒女情長,耽誤了整個程式。
下面我來舉一個簡單的例子(為了程式碼儘量簡單,使用了C++11的thread library)
#include <iostream> #include <thread> #include <mutex> #include <chrono> using namespace std; mutex m1,m2; void func_2() { m2.lock(); cout<< "about to dead_lock"<<endl; m1.lock(); } void func_1() { m1.lock(); chrono::milliseconds dura( 1000 );// delay to trigger dead_lock this_thread::sleep_for( dura ); m2.lock(); } int main() { thread t1(func_1); thread t2(func_2); t1.join(); t2.join(); return 0; }
編譯程式碼
$> g++ -Wall -std=c++11 dead_lock_demo.cpp -o dead_lock_demo -g -pthread
執行程式,發現程式列印出“about to dead_lock” 就不動了,現在我們使用gdb來除錯。注意gdb的版本要高於7.0,之前使用過gdb6.3除錯多執行緒是不行的。
在這之前需要先產生core dump檔案:
$> ps -aux | grep dead_lock_demo
找出 dead_lock_demo 執行緒號,然後:
$> kill -11 pid
此時會生成core dump 檔案,在我的系統上名字就是 core
然後除錯:
$> gdb dead_lock_demo core
$> thread apply all bt
下面來看一下實際的過程:
從上圖可以看出兩個執行緒都阻塞在wait上,而且還給出了在哪一行程式碼中,很容易就定位到產生死鎖的位置。
相關文章
- Java多執行緒(五):死鎖Java執行緒
- java多執行緒(5)死鎖Java執行緒
- Java多執行緒7:死鎖Java執行緒
- OD除錯多執行緒除錯執行緒
- 多執行緒-死鎖問題概述和使用執行緒
- Java除錯教程--多執行緒除錯(轉)Java除錯執行緒
- GDB多執行緒除錯分析執行緒除錯
- 執行緒中的死鎖執行緒
- GCD&&執行緒死鎖GC執行緒
- GCD 之執行緒死鎖GC執行緒
- gdb多執行緒多程序除錯命令執行緒除錯
- JavaSE_多執行緒入門 執行緒安全 死鎖 狀態 通訊 執行緒池Java執行緒
- Java多執行緒-死鎖的出現和解決Java執行緒
- 死鎖:多執行緒同時刪除唯一索引上的同一行執行緒索引
- 多執行緒_鎖執行緒
- gdbserver 移植與多執行緒除錯Server執行緒除錯
- 如何處理執行緒死鎖執行緒
- Java 實現執行緒死鎖Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- 23、Java併發性和多執行緒-重入鎖死Java執行緒
- python多執行緒程式設計4: 死鎖和可重入鎖Python執行緒程式設計
- 【Java】【多執行緒】同步方法和同步程式碼塊、死鎖Java執行緒
- java多執行緒中的死鎖、活鎖、飢餓、無鎖都是什麼鬼?Java執行緒
- iOS多執行緒安全-13種執行緒鎖?iOS執行緒
- 多執行緒(2)-執行緒同步互斥鎖Mutex執行緒Mutex
- java多執行緒–同步鎖Java執行緒
- Java多執行緒-無鎖Java執行緒
- Python | 多執行緒死鎖問題的巧妙解決方法Python執行緒
- java 執行緒淺解03[執行緒同步以及經典死鎖]Java執行緒
- Java執行緒面試題(02) Java執行緒中如何避免死鎖Java執行緒面試題
- java多執行緒:執行緒同步synchronized(不同步的問題、佇列與鎖),死鎖的產生和解決Java執行緒synchronized佇列
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI
- Python 多執行緒和鎖Python執行緒
- 多執行緒鎖的問題執行緒
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- JAVA多執行緒詳解(3)執行緒同步和鎖Java執行緒
- 多執行緒程式設計的鎖問題解析(鎖競爭死鎖活鎖及Date Race等)執行緒程式設計
- 誰在死鎖Mutex——用Windbg查詢Mutex死鎖所有者執行緒Mutex執行緒