最近工作遇到很多问题,尤其是线程死锁,crash这样的bug。 前几天遇到的一个crash , 用windbg调试的时候的发现每次报错的位置都不一样,仿佛是随机的,后来找一个前辈来帮忙分析,也没有找到问题。后来通过代码屏蔽的方法,发现是我的网络通信类有问题,于是重新写了通信类,总算是表面上解决了问题。自己对windbg也一知半解的,所以今天就特意找了个死锁的例子,用windbg来分析。
偷懒了 ,直接从网上找个一段死锁的代码,如下:
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <iostream>
CRITICAL_SECTION g_cs1;
CRITICAL_SECTION g_cs2;
DWORD WINAPI Worker(LPVOID lpParam)
{
if((int)lpParam == 7)
{
while(1)
{
printf("Worker[%x]: 就我活着\n", GetCurrentThreadId());
Sleep(10000);
}
}
else
{
printf("Worker[%x]:准备进入临界段---g_cs2\n", GetCurrentThreadId());
EnterCriticalSection(&g_cs2);
printf("Worker[%x]:成功进入临界段---g_cs2\n", GetCurrentThreadId());
printf("Worker[%x]:准备进入临界段---g_cs1\n", GetCurrentThreadId());
EnterCriticalSection(&g_cs1);
printf("Worker[%x]:成功进入临界段---g_cs1\n", GetCurrentThreadId());
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&g_cs1);
InitializeCriticalSection(&g_cs2);
printf("main[%x]: 准备进入临界段 g_cs1\n", GetCurrentThreadId());
EnterCriticalSection(&g_cs1);
printf("main[%x]: 成功进入临界段 g_cs1\n", GetCurrentThreadId());
HANDLE hThread[8];
for(int i=0; i<8; i++)
{
hThread[i] = CreateThread(NULL, 0, Worker, (LPVOID)i, 0, NULL);
}
printf("main[%x]: 准备进入临界段 g_cs2\n", GetCurrentThreadId());
EnterCriticalSection(&g_cs2);
printf("main[%x]: 成功进入临界段 g_cs2!\n", GetCurrentThreadId());
return 0;
}
编译运行后效果如下:
由于主线程率先进入了临界区1不离开, 就导致其他无法进入临界区1. 线程15dc虽然请求到临界区2,但是却无法进入临界区1.; 主线程和 15dc都再等待对方的资源,结果导致死锁。现在用windbg附加上进程, 输入命令 ~*kb 查看所有线程
发现有8个线程 都有类似的输出:(因为第七个个线程是不进入临界区的)
0095feb4 77c68cd8 00000000 00000000 77c522a0 ntdll!ZwWaitForSingleObject+0x15
ntdll!ZwWaitForSingleObject+0x15 这里便是问题的关键,我们可以看到所有的线程都在等待0x15, 难道他们都在等待0x15, 其实这里仅供参考。我从资料上看到说得是这个对象很可能是windbg给出了错误的信息
紧接着的输出变给出了当前线程运行到代码的哪一行:
0095fef4 761c339a 00000000 0095ff40 77c69ef2 TestDeadLock!Worker+0x7d [e:\projects\testdeadlock\testdeadlock\testdeadlock.cpp @ 31]
testdeadlock.cpp 文件第 31行。。。