一. 准备工作

这里一个有关键区锁死问题的程序,运行之后依次点击“CS锁死”按钮、右上角退出按钮,程序就会卡死。(图1)

对于眼下的这个问题,界面完全失去响应,这说明负责消息处理的UI线程阻塞了。对于几乎所有的windows GUI程序,编号为0的初始线程就是UI线程,windows发现该界面一段时间没有消息响应之后就会在标题后面加上“(未响应)”。

二. 开始调试

启动Windbg,附加到执行进程(F6),这时如果在windbg输出的上面看到如下内容(图2),说明第一步的环境变量设置生效了。

~*knv3 查看各个线程的调用堆栈(图3),数字3表示显示的堆栈深度,省略即显示完整堆栈。

#0号线的栈帧0表示线程程阻塞在NtWaitForSingleObject函数,MSDN得知该函数原型为:

NTSTATUS WINAPI NtWaitForSingleObject(
_In_ HANDLE Handle,
_In_ BOOLEAN Alertable,
_In_ PLARGE_INTEGER Timeout
);

第一个参数Handle为其等待的句柄,第三个参数TimeOut为超时时间。

同样从栈帧0得知NtWaitForSingleObject正在等待句柄000000c4,超时时间为0(即没信号就一直等待)。

!handle 000000c4 f 命令查看该句柄的信息(图4):

现在我们知道c4句柄就是线程20d0的句柄,主线程在退出的时候等待该线程退出,而该线程一直没有退出,所以主线程卡死了。

根据图3得知20d0线程就是#1线程,~1kvn 查看该线程完整堆栈(图5):

栈帧00 NtWaitForSingleObject 表示线程在等待000000c0句柄。

!handle 000000c0 f 得知c0句柄为事件句柄:

0:002> !handle c0 f
Handle c0
Type Event
Attributes 0
GrantedAccess 0x100003:
Synch
QueryState,ModifyState
HandleCount 2
PointerCount 4
Name <none>
Object Specific Information
Event Type Auto Reset
Event is Waiting

!locks 查看进程中哪些锁处于锁定状态(图6):

从第一行结果可以得知是gcsName临界区(需要有pdb才会显示具体变量名)处于锁定状态。

其实,我们从栈帧02 RtlEnterCriticalSection 也可以很快的知道该线程一直在等待进入关键区。

经过分析,知道程序如法退出的原因了:线程#1中的关键区gcsName处于锁定状态(也就是一直等待进入关键区),导致线程#1阻塞无法执行。又因主线程在退出的时候执行了WaitForSingleObject等待#1线程,从而导致主线程卡死。

关键区机制主要是通过下面这样的RTL_CRITICAL_SECTION结构来实现的,可以通过dt 命令查看该结构定义:

0:002> dt RTL_CRITICAL_SECTION
Test1!RTL_CRITICAL_SECTION
+0x000 DebugInfo : Ptr32 _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : Int4B
+0x008 RecursionCount : Int4B
+0x00c OwningThread : Ptr32 Void
+0x010 LockSemaphore : Ptr32 Void
+0x014 SpinCount : Uint4B

其中,LockCount字段用来标识关键区的锁状态,RecursionCount字段用来记录递归次数,用来支持同一个线程多次进入关键区,OwningThread字段用来记录进入(拥有)关键区的线程ID,LockSemaphore用来记录这个关键区对应的事件对象,当有线程需要等待这个关键区时,便是通过等待这个事件来做到的,这个事件对象是按需创建的,如果LockSemaphore为NULL表示这个关键区从来没有线程在此等待过。

通过图6中的OwningThread=738得知,关键区被线程ID为738的线程所拥有,即Enter之后一直没有Leave。

知道了是哪个线程获取了关键区但没有释放,就可以很容易的在代码中定位问题了。

!locks 没有显示LockSemaphore字段,我们可以通过!cs -l 命令获取更为全面的关键区信息:

从上图可以看到LockSemaphore=0xC0,正好是#1线程NtWaitForSingleObject的事件对象。

Windbg调试关键区(CriticalSection)死锁的更多相关文章

  1. [原]调试实战——使用windbg调试TerminateThread导致的死锁

    原调试debugwindbg死锁deadlock 前言 项目里的一个升级程序偶尔会死锁,查看dump后发现是死在了ShellExecuteExW里.经验少,不知道为什么,于是在高端调试论坛里发帖求助, ...

  2. [原]调试实战——使用windbg调试excel启动时死锁

    原调试debugwindbg死锁deadlock 前言 这是几年前在项目中遇到的一个死锁问题,在博客园发布过.我对之前的笔记进行了整理重新发布于此. 本文假设小伙伴们知道一些基本概念,比如什么是.du ...

  3. Windbg调试互斥体(Mutex)死锁

    一. 测试代码 #include <windows.h> #include <tchar.h> #include <process.h> HANDLE hMutex ...

  4. [原]调试实战——使用windbg调试DLL卸载时的死锁

    原调试debugwindbg死锁deadlock 前言 最近我们的程序在退出时会卡住,调查发现是在卸载dll时死锁了.大概流程是这样的:我们的dll在加载的时候会创建一个工作线程,在卸载的时候,会设置 ...

  5. WinDBG 调试命令大全

    转载收藏于:http://www.cnblogs.com/kekec/archive/2012/12/02/2798020.html  #调试命令窗口 ++++++++++++++++++++++++ ...

  6. WinDbg调试流程的学习及对TP反调试的探索

    基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...

  7. Windows多线程同步系列之二-----关键区

    关键区对象为:CRITICAL_SECTION 当某个线程进入关键区之后,其他线程将阻塞等待,知道该线程释放关键区的拥有权. 关键区同步主要有以下几个API 初始化关键区对象,无返回值,传入一个关键区 ...

  8. windows多线程(四) 关键段 CriticalSection

    一.问题回顾 我们上一篇文章最后的程序的输出 g_Count 的值不是每次都正确,原因是没有对全局资源 g_Count 进行互斥访问(就是同一时刻只能由一个线程访问),接下来我们就来说一下使用关键段来 ...

  9. windbg调试堆破坏

    堆破坏 所谓的堆破坏,是说没控制好自己的指针,把不属于你分配的那块内存给写覆盖了.这块内存可能是你程序的数据,也可能是堆的管理结构.那么这个会导致怎样的后果呢?可能的情况我们来yy下 把程序里的计算结 ...

随机推荐

  1. zepto.js 的tap事件中点击一次触发两次事件

    html代码: <div class="xh-lxx-cart-count1"> <span class="minus">-</s ...

  2. Python面向对象编程(二)

    1.继承与派生 上文我们已经说过,Python中一切皆对象.我们从对象中抽取了共同特征和技能,得到了类的概念.类与类之间也有共同特征,我们可以从有共同特征和技能的类中提取共同的技能和特征,叫做父类. ...

  3. Python爬虫从入门到放弃(十九)之 Scrapy爬取所有知乎用户信息(下)

    在上一篇文章中主要写了关于爬虫过程的分析,下面是代码的实现,完整代码在:https://github.com/pythonsite/spider items中的代码主要是我们要爬取的字段的定义 cla ...

  4. Java类加载机制、类加载器和反射机制-思维导图

    参考文献: 1. <深入理解JVM虚拟机>

  5. 什么是B-Tree

    B-Tree就是我们常说的B树,一定不要读成B减树,否则就很丢人了.B树这种数据结构常常用于实现数据库索引,因为它的查找效率比较高. B-Tree与二叉查找树的对比 我们知道二叉查找树查询的时间复杂度 ...

  6. (转)Spring Boot Junit单元测试

    场景:在项目开发中要测试springboot工程中一个几个dao和service的功能是否正常,初期是在web工程中进行要素的录入,工作量太大.使用该单元测试大大减小了工作强度. Junit这种老技术 ...

  7. Spring mybatis源码篇章-MybatisDAO文件解析(二)

    前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(一) 默认加载mybatis主文件方式 XMLConfigBuilder ...

  8. HDOJ2002-计算球体面积

    Problem Description 根据输入的半径值,计算球的体积.   Input 输入数据有多组,每组占一行,每行包括一个实数,表示球的半径.   Output 输出对应的球的体积,对于每组输 ...

  9. maven相关的学习资料

    1, maven的settings配置文件详解: http://blog.csdn.net/jinshuaiwang/article/details/23686099 2,maven原理---翡青的博 ...

  10. Web项目、Http协议简介

    Web 静态web项目 静态web项目就是一个文件夹.静态Web项目 就是文件夹中都是静态资源. 如何将web项目部署到tomcat? 将web项目的文件夹复制到webapps目录下.比如把test文 ...