WinDbg -- 除錯互斥體(Mutex)死鎖
阿新 • • 發佈:2019-01-28
一. 演示用例
#include <windows.h>
#include <tchar.h>
#include <process.h>
HANDLE hMutexA = NULL;
HANDLE hMutexB = NULL;
unsigned __stdcall ThreadProc1(void * pArg) {
WaitForSingleObject(hMutexA, INFINITE);
Sleep(500);
WaitForSingleObject(hMutexB, INFINITE);
printf("+++\n" );
ReleaseMutex(hMutexB);
ReleaseMutex(hMutexA);
return 0;
}
unsigned __stdcall ThreadProc2(void * pArg) {
WaitForSingleObject(hMutexB, INFINITE);
Sleep(500);
WaitForSingleObject(hMutexA, INFINITE);
printf("...\n");
ReleaseMutex(hMutexA);
ReleaseMutex(hMutexB);
return 0;
}
int main()
{
hMutexA = CreateMutex(NULL, FALSE, TEXT("MutexA"));
hMutexB = CreateMutex(NULL, FALSE, TEXT("MutexB"));
// 啟動執行緒
HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadProc2, NULL, 0, NULL);
getchar();
// 等待執行緒退出並關閉控制代碼
if (hThread1) {
WaitForSingleObject(hThread1, INFINITE);
CloseHandle(hThread1);
}
if (hThread2) {
WaitForSingleObject(hThread2, INFINITE);
CloseHandle(hThread2);
}
// 關閉控制代碼
if(hMutexA)
CloseHandle(hMutexA);
if(hMutexB)
CloseHandle(hMutexB);
return 0;
}
二. 死鎖原因
程式生成了2個執行緒(執行緒1、執行緒2)和2個互斥體MutexA和MutexB。
觀察執行緒執行程式碼可知,這是一個典型的死鎖用例,2個執行緒相互等待。
執行緒1: 擁有MutexA –> 過一段時間(sleep) —> 想擁有MutexB
執行緒2: 擁有MutexB –> 過一段時間(sleep) —> 想擁有MutexA
執行緒1想擁有屬於執行緒2的MutexB,而執行緒2卻想擁有屬於執行緒1的MutexA,互不鬆手,就只能都等著了。
三. Windbg除錯
~*kvn
檢視所有執行緒呼叫堆疊:
從執行緒#1棧幀03可以看到其正在等待控制代碼00000038。
從執行緒#2棧幀03可以看到其正在等待控制代碼00000034。
即:
執行緒#1(ID:22f4)—>等待控制代碼38
執行緒#2(ID:33bc)—> 等待控制代碼34
使用!handle
命令檢視控制代碼00000034和00000038是什麼型別:
從圖中可以看到:
控制代碼00000034為名為MutexA的互斥體,被執行緒ID:2264 擁有。
控制代碼00000038為名為MutexB的互斥體,被執行緒ID:33bc 擁有。
即:
執行緒#1(ID:22f4)等待00000038(互斥體MutexA ),擁有00000034(互斥體MutexB)
執行緒#2(ID:33bc)等待控制代碼00000034(互斥體MutexB ),擁有00000038(互斥體MutexA)