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