windbg之经典死锁案例 及 相关命令

1  先上死锁代码 如下:

#include "stdafx.h"
#include <mutex>
#include <thread>
#include <windows.h>

// windows系统中 std::mutex内部是通过Event内核对象实现的,而不是CRITICAL_SECTION
std::mutex mtx0;
std::mutex mtx1;

CRITICAL_SECTION cs0;
CRITICAL_SECTION cs1;

int _tmain(int argc, _TCHAR* argv[])
{
    InitializeCriticalSectionAndSpinCount(&cs0, 4000);
    InitializeCriticalSectionAndSpinCount(&cs1, 4000);

    std::thread thread0([]{
        EnterCriticalSection(&cs0);
        std::this_thread::sleep_for(std::chrono::seconds(3));
        EnterCriticalSection(&cs1);
    });

    std::thread thread1([]{
        EnterCriticalSection(&cs1);
        std::this_thread::sleep_for(std::chrono::seconds(3));
        EnterCriticalSection(&cs0);
    });

    printf("enter dead lock...");
    thread0.join();  // 主线程将永远阻塞在这里,因为thread0 和 thread1之间发生了死锁
    thread1.join();
    printf("leave dead lock...");

    return 0;
}

2 release下,去掉pdb,编译出exe,运行如下:

 

3 将windbg附加到此进程中:

 

 

4 查看主线程堆栈: ~0kb      

~0kb 命令简介: 0是主线程的序号  kb表示输出调用堆栈中函数的前3个参数;(~波浪线就像一个线头thread,所以线程相关命令都由~开头) 查看线程堆栈的详细命令参见:https://blog.csdn.net/luchengbiao/article/details/89240601

通过堆栈可知  主线程在等待(WaitForSingleObject )一个内核对象受信,故而阻塞!!!

5 查看句柄信息: !handle 0000014c f

易知 函数[Nt] WaitForSingleObject [Ex] 是在阻塞等待一个内核对象受信,其中第一个参数值就是要相应的内核对象句柄,此处就是0x0000014c;

所以通过命令 !handle 0000014c f  命令查看内核对象句柄的全部信息(full information) (查看内核对象句柄的信息的详细命令参见https://blog.csdn.net/luchengbiao/article/details/89241054):

可知 此内核对象是一个线程,线程id是 13c4.22b4     其中13c4表示所属进程id 22b4表示线程id

6 查找到相应线程: ~*kb

~*kb 命令简介: *通配符表示所有线程  kb表示输出调用堆栈中函数的前3个参数;查看线程堆栈的详细命令参见:https://blog.csdn.net/luchengbiao/article/details/89240601

也可以通过线程id直接查找相应线程,~~[0x22b4], 参见step8

可见 线程id是13c4.22b4 的是线程1,透过其堆栈又可知 线程1阻塞在一个CRITIAL_SECTION关键段上

 

7 查看关键段CRITIAL_SECTION: !cs 00073470

!cs 00073470 命令简介:查看地址是00073470的CRITIAL_SECTION对象的信息,详细命令参见https://blog.csdn.net/luchengbiao/article/details/89241054

LOCKED: 表示此cs已被加锁

OwingThread:表示锁定此cs的线程id

RecursionCount:表示重入次数; 何为重入: 在同一个线程中可以多次EnterCriticalSection同一个cs,并记录重入的次数;C++11中的std::recursive_mutex类此;

SpinCount:表示此cs的自旋次数,可在 InitializeCriticalSectionAndSpinCount(&cs0, 4000)的第二个参数指定 0x0fa0 == 4000; 自旋是一种busy wait机制,相应的还有sleep wait:先最多尝试4000次 busy,如果还不能成功EnterCritialSection(即own the cs)则才进入sleep wait,陷入内核等待唤醒,内部由Event相应实现,参见windows核心编程。

可知此cs已被id为0x000024c8的线程加锁

8 再次查找线程:

~~[0x000024c8]   通过线程id查找相应线程

~2kb

可见 线程id是24c8 的是线程2,通过其堆栈又可知 线程2阻塞在一个CRITIAL_SECTION关键段上

9 再次查看关键段CRITIAL_SECTION: !cs 00073488

 

10 再次查找线程:

~~[000022b4]

11 发现循环等待(即死锁) :线程2在等待线程1拥有的锁, 线程1在等待线程2拥有的锁!!!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值