一. 准备工作

这里一个有关键区锁死问题的程序,运行之后依次点击“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. 企业QQ客服的添加

    商城项目需要用腾讯的企业QQ客服,但默认提供的是一个链接,点击后弹出一个新页面, 请确认 确认打开QQ与营销QQ4009928310对话? 点确认才弹出聊天窗口,并不是需求想要的效果,经过一番折腾联系 ...

  2. Spark的误解-不仅spark是内存计算,hadoop也是内存计算

    市面上有一些初学者的误解,他们拿spark和hadoop比较时就会说,Spark是内存计算,内存计算是spark的特性.请问在计算机领域,mysql,redis,ssh框架等等他们不是内存计算吗?依据 ...

  3. MySQL中的联合索引学习教程

    MySQL中的联合索引学习教程 这篇文章主要介绍了MySQL中的联合索引学习教程,其中谈到了联合索引对排序的优化等知识点,需要的朋友可以参考下   联合索引又叫复合索引.对于复合索引:Mysql从左到 ...

  4. eclipse中tomcat 中server location灰色,如何修改?

    Eclipse中tomcat service设置选择window ----show view---services可以看到服务的面板双击tomcat进入配置界面Service Locations(Sp ...

  5. 初学安卓开发随笔之 Menu、toast 用法、活动的四种启动模式 以及 一个方便的Base活动类使用方法

    Toast toast 是安卓系统的一种非常棒的提醒方式 首先定义一个弹出Toast的触发点,比如可以是按钮之类 其中 Toast.LENGTH_SHORT是指显示时长 还有一个内置变量为Toast. ...

  6. Django中ORM模型总结(一)[概述,查询语句]

    理解ORM框架 概述 O:(objects)->类和对象. R:(Relation)->关系,关系数据库中的表格. M:(Mapping)->映射. 作用: 可以通过类和类对象就可以 ...

  7. rabbitMQ教程(二)一篇文章看懂rabbitMQ

    一.rabbitMQ是什么: RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上. 学过websocket的来理解rabbitMQ应该是 ...

  8. 最通俗易懂的javascript变量提升

    a = 'ghostwu'; var a; console.log( a ); 在我没有讲什么是变量提升,以及变量提升的规则之前, 或者你没有学习过变量提升,如果按照现有的javascript理解, ...

  9. 小明历险记:规则引擎drools教程一

    小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...

  10. 用 Node.js 把玩一番 Alfred Workflow

    插件地址(集成Github.掘金.知乎.淘宝等搜索) 作为 Mac 上常年位居神器榜第一位的软件来说,Alfred 给我们带来的便利是不言而喻的,其中 workflow(工作流) 功不可没,在它上面可 ...