用gdb指令碼解決死鎖的除錯方法(由pthread_mutex_lock引起的死鎖)
首先給出gdb定位死鎖的指令碼:
#deadlock_debug_gdb.cmd set pagination off set logging file gdb.log set logging overwrite set logging on start set $lock_addr=pthread_mutex_lock set $unlock_addr=pthread_mutex_unlock break *$lock_addr break *$unlock_addr while 1 continue if $pc != $lock_addr && $pc != $unlock_addr quit end bt end #不出現Type<Enter>to continue的提示訊息 #設定日誌檔案gdb.log #寫日誌模式為覆蓋寫 #開啟日誌功能 #在main函式第一句設定斷點並開始執行程式 #記錄lock和unlock的系統函式地址並給他們設定斷點 #除錯物件程式執行後若出現死鎖,立刻結束程式(quit,等效使用者Ctrl-C) #bt就是每次有鎖操作時就列印堆疊到log
該gdb指令碼deadlock_debug_gdb.cmd的功能主要是:
此命令檔案會在pthread_mutex_lock()和pthread_mutex_unlock()被呼叫時顯示backtrace,並將backtrace資訊記錄到gdb.log日誌檔案中。
使用gdb指令碼deadlock_debug_gdb.cmd的除錯死鎖方法是:
step1:gdb除錯執行a.out程式,執行時自行執行gdb指令碼檔案
$gdb ./a.out -x ./deadlock_debug_gdb.cmd
.........
當a.out死鎖時,程式會被gdb指令碼中斷,從a.out開始執行到出現死鎖中斷的整個過程中pthread_mutex_lock和pthread_mutex_unlock的堆疊都在日誌中gdb.log
step2:使用shell命令找到gdb.log中所有包含pthread_mutex_lock和pthread_mutex_unlock的所有行
$cat gdb.log | grep -Al "^#0.*pthread_mutex_" | set s/from\.*$// | sed s/.*\in\//
............
pthread_mutex_lock()
thr (arg=0x0) at a.out.c : 18
............
pthread_mutex_lock()
cnt_reset() at a.out.c:10
又上可知,最後a.out.c原始檔在18號加鎖後(pthread_mutex_lock()),又在第10行再次加鎖(pthread_mutex_lock())導致了a.out的死鎖。
下面要做的就是分析下為啥18行加鎖後沒有釋放鎖導致了第10行加鎖時導致了死鎖。
以上就是使用gdb指令碼除錯pthread_mutex_lock死鎖引起的程式停止響應的方法,到此本文已經結束。
====================================================================================
本文已經結束了,但是再工作中遇到過導致pthread_mutex_lock引起死鎖的場景,這裡記錄下,符合上面死鎖的一個示例。
工作中遇到的是Semaphore訊號量和pthread_mutex_lock共同作用導致的死鎖,表面上看是訊號量sem和互斥量mutex,主要還是mutex的使用不合理導致的死鎖。
導致死鎖的程式碼結構如下所示:
void fun1()
{
m_mutex.enter();
........
m_sem.pend();
........
m_mutex.leave();
}
void fun2()
{
m_mutex.enter()
..........
m_sem.post();
..........
m_mutex.leave();
}
如下流程可以復現死鎖:
fun1()執行m_mutex.enter();成功
fun1()接著執行m_sem.pend(),此時fun1會pend停在此行(等待fun2()的訊號量post)
fun2()執行m_mutex.enter();,此時fun2執行enter()來獲取mutex(fun2必須停在此行等到fun1執行leave()後才能執行下行程式碼m_sem.post())
fun2()無法執行m_sem.post()
由上可知:fun1()等待fun2()進行訊號量執行post後才能釋放m_mutex,但是fun2需要獲取到m_mutex才能進行訊號量post.
推理可知fun1需要fun2的m_sem.post()才會m_mutex.leave(),但是fun2()需要fun1的m_mutex.leave()才能m_sem.post(),所以出現了fun1和fun2的死鎖問題。
仔細研究可知,fun1使用互斥訊號量m_mutex不當所致:沒有及時釋放m_mutex所致。
一種修改方法:
viod fun1()
{
m_mutex.enter();
........
m_mutex.leave();//及時釋放m_mutex,以防其他介面獲取鎖時導致死鎖
m_sem.pend();
m_mutex.enter();
.......
m_mutex.leave();
}
void fun2()
{
m_mutex.enter()
..........
m_sem.post();
..........
m_mutex.leave();
}
ps:可能還有其他方法。
《完》