Windbg调试关键区(CriticalSection)死锁
一. 准备工作
这里一个有关键区锁死问题的程序,运行之后依次点击“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)死锁的更多相关文章
- [原]调试实战——使用windbg调试TerminateThread导致的死锁
原调试debugwindbg死锁deadlock 前言 项目里的一个升级程序偶尔会死锁,查看dump后发现是死在了ShellExecuteExW里.经验少,不知道为什么,于是在高端调试论坛里发帖求助, ...
- [原]调试实战——使用windbg调试excel启动时死锁
原调试debugwindbg死锁deadlock 前言 这是几年前在项目中遇到的一个死锁问题,在博客园发布过.我对之前的笔记进行了整理重新发布于此. 本文假设小伙伴们知道一些基本概念,比如什么是.du ...
- Windbg调试互斥体(Mutex)死锁
一. 测试代码 #include <windows.h> #include <tchar.h> #include <process.h> HANDLE hMutex ...
- [原]调试实战——使用windbg调试DLL卸载时的死锁
原调试debugwindbg死锁deadlock 前言 最近我们的程序在退出时会卡住,调查发现是在卸载dll时死锁了.大概流程是这样的:我们的dll在加载的时候会创建一个工作线程,在卸载的时候,会设置 ...
- WinDBG 调试命令大全
转载收藏于:http://www.cnblogs.com/kekec/archive/2012/12/02/2798020.html #调试命令窗口 ++++++++++++++++++++++++ ...
- WinDbg调试流程的学习及对TP反调试的探索
基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...
- Windows多线程同步系列之二-----关键区
关键区对象为:CRITICAL_SECTION 当某个线程进入关键区之后,其他线程将阻塞等待,知道该线程释放关键区的拥有权. 关键区同步主要有以下几个API 初始化关键区对象,无返回值,传入一个关键区 ...
- windows多线程(四) 关键段 CriticalSection
一.问题回顾 我们上一篇文章最后的程序的输出 g_Count 的值不是每次都正确,原因是没有对全局资源 g_Count 进行互斥访问(就是同一时刻只能由一个线程访问),接下来我们就来说一下使用关键段来 ...
- windbg调试堆破坏
堆破坏 所谓的堆破坏,是说没控制好自己的指针,把不属于你分配的那块内存给写覆盖了.这块内存可能是你程序的数据,也可能是堆的管理结构.那么这个会导致怎样的后果呢?可能的情况我们来yy下 把程序里的计算结 ...
随机推荐
- Spring Boot 系列(四)静态资源处理
在web开发中,静态资源的访问是必不可少的,如:图片.js.css 等资源的访问. spring Boot 对静态资源访问提供了很好的支持,基本使用默认配置就能满足开发需求. 一.默认静态资源映射 S ...
- 理解梯度下降法(Gradient Decent)
1. 什么是梯度下降法? 梯度下降法(Gradient Decent)是一种常用的最优化方法,是求解无约束问题最古老也是最常用的方法之一.也被称之为最速下降法.梯度下降法在机器学习中十分常见,多用 ...
- .NET Core 事件总线,分布式事务解决方案:CAP
背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景 ...
- css3 变换 transform(2D)
一.transform变换 可做拉伸.压缩.旋转.偏移的效果.需加各个浏览器前缀. 二.transform-origin 为transform属性值的基点,默认值为元素的中心位置,即以元素左上角为坐标 ...
- ConcurrentLinkedQueue 源码 since java1.5
1 父类 java.lang.Object 继承者 java.util.AbstractCollection<E> 继承者 java.util.AbstractQueue<E> ...
- Window下Jenkins的安装
之前没接触过持续集成工具,之前只是了解了下自动化部署,最近一直在看自动化集成这块,发现要学的东西好多好多,可能在小公司用的不多,但如果在大公司,如果每个项目都要手动build.deploy的话那也太耗 ...
- Python爬取百度贴吧数据
本渣除了工作外,在生活上还是有些爱好,有些东西,一旦染上,就无法自拔,无法上岸,从此走上一条不归路.花鸟鱼虫便是我坚持了数十年的爱好. 本渣还是需要上班,才能支持我的业余爱好.上班时间还是尽量访问外网 ...
- SignalR在ASP.NET MVC中的应用
一.简介 ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接的客户端变得 ...
- echarts添加点击事件
由于工作需要,需要用echarts 进行展示图表,却又个新的需求,要点击展示的地方,同时下面出现table展示内容 如图所示: 一开始找了好多博客,发现都不好用,大部分都是用到了 var ecConf ...
- ES6数组扩展
前面的话 数组是一种基础的JS对象,随着时间推进,JS中的其他部分一直在演进,而直到ES5标准才为数组对象引入一些新方法来简化使用.ES6标准继续改进数组,添加了很多新功能.本文将详细介绍ES6数组扩 ...