本文通过一个实例来讲解如何使用 WinDbg 来调试 Windows Mutex 死锁的问题。
演示用例
下面是一个会导致 Mutex 死锁的程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #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)
文章图片带有“CSDN”水印的说明:
由于该文章和图片最初发表在我的CSDN 博客中,因此图片被 CSDN 自动添加了水印。