1. 程式人生 > >WinDbg -- 除錯互斥體(Mutex)死鎖

WinDbg -- 除錯互斥體(Mutex)死鎖

一. 演示用例

#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)