本文通过一个实例来讲解如何使用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 自动添加了水印。