当前位置: 首页 > article >正文

临界区死锁和死循环

1.临界区

目录

1.临界区

2. 经典死锁案例:

3.查找死循环案例


使用CRITICAL_SECTION 结构来保证不会有多个线程重入被保护的代码段
实现在用户态的同步机制,相对内核对象来说,开销更小
适用于同步同一进程内的多个线程

如:
CRITICAL_SECTION g_cs;EnterCriticalSection(&g_cs);
//以原子方式访问共享资源
..... //do something
LeaveCriticalSection(&g_cs);RTL_CRITICAL_SECTION 结构如下:
struct RTL_CRITICAL_SECTION
{PRTL_CRITICAL_SECTION_DEBUG DebugInfo;LONG LockCount;LONG RecursionCount;HANDLE OwningThread;HANDLE LockSemaphore;ULONG_PTR SpinCount;
};

LockCount字段,初始值为-1,被线程拥有后,大于等于0,反映等待和已经进入关键区的线程数RecursionCount字段,此字段包含所有者线程已经获得该临界区的次数。如果该数值为零,下一个尝试获取该临界区的线程将会成功。
OwningThread字段,拥有线程(已经进入临界区)的句柄。
LockSemaphore字段,唤醒等待的线程在初始化临界区结构时,系统会分配一个RTL_CRITICAL_SECTION_DEBUG结构,每个临界区的调试结构依靠ProcessLocksList字段相互联系在一起。
SpinCount 仅用于多处理器系统。MSDN文档对此字段进行如下说明:“在多处理器系统中,如果该临界区不可用,调用线程将在对与该临界区相关的信号执行等待操作之前,旋转 dwSpinCount 次。如果该临界区在旋转操作期间变为可用,该调用线程就避免了等待操作。”旋转计数可以在多处理器计算机上提供更佳性能,其原因在于在一个循环中旋转通常要快于进入内核模式等待状态。此字段默认值为零,但可以用 InitializeCriticalSectionAndSpinCount API 将其设置为一个不同值。
临界区的调试支持,RTL_CRITICAL_SECTION_DEBUG结构如下:

struct _RTL_CRITICAL_SECTION_DEBUG
{WORD   Type;WORD   CreatorBackTraceIndex;RTL_CRITICAL_SECTION *CriticalSection;LIST_ENTRY ProcessLocksList;DWORD EntryCount;DWORD ContentionCount;DWORD Spare[ 2 ];
}

这一结构由 InitializeCriticalSection 分配和初始化。它既可以由 NTDLL内的预分配数组分配,也可以由进程堆分配。RTL_CRITICAL_SECTION的这一伴随结构包含一组匹配字段,具有迥然不同的角色:有两个难以理解,随后两个提供了理解这一临界区链结构的关键,两个是重复设置的,最后两个未使用。

下面是对 RTL_CRITICAL_SECTION 字段的说明。
Type 此字段未使用,被初始化为数值 0。
CreatorBackTraceIndex 此字段仅用于诊断情形中。在注册表项
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File ExecutionOptions\YourProgram 之下是 keyfield、GlobalFlag 和 StackTraceDatabaseSizeInMb值。注意,只有在运行稍后说明的 Gflags 命令时才会显示这些值。这些注册表值的设置正确时,CreatorBackTraceIndex
字段将由堆栈跟踪中所用的一个索引值填充。在 MSDN 中搜索 GFlags 文档中的短语“create user mode stack trace database”和“enlarging the user-mode stack trace database”,可以找到有关这一内容的更多信息。
CriticalSection 指向与此结构相关的 RTL_CRITICAL_SECTION。
图1 说明该基础结构以及 RTL_CRITICAL_SECTION、RTL_CRITICAL_SECTION_DEBUG 和事件链中其他参与者之间的关系。

图 1 临界区的关系

ProcessLocksList LIST_ENTRY 是用于表示双向链表中节点的标准 Windows数据结构。RTL_CRITICAL_SECTION_DEBUG 包含了链表的一部分,允许向前和向后遍历该临界区。
EntryCount/ContentionCount 这些字段在相同的时间、出于相同的原因被递增。这是那些因为不能马上获得临界区而进入等待状态的线程的数目。与 LockCount 和 RecursionCount字段不同,这些字段永远都不会递减。
Spares这两个字段未使用,甚至未被初始化(尽管在删除临界区结构时将这些字段进行了清零)。
即使 RTL_CRITICAL_SECTION_DEBUG中包含多个字段,它也是常规临界区结构的必要成分。事实上,如果系统恰巧不能由进程堆中获得这一结构的存储区,InitializeCriticalSection
将返回为 STATUS_NO_MEMORY 的 LastError 结果,然后返回处于不完整状态的临界区结构。

2. 经典死锁案例:

启动windbg 附加MulThrds.exe

·1.~*  查看所有线程

2.~* k 查看所有线程堆栈

发现有几个线程都在等待进入同一个临界区

3.切换其中某一个线程,查看堆栈,如切到换10号线程

4.查看临界区 !cs 0040b32c

5.查看死锁的临界区,刚好也是0040b32c

拥有的线程是0x00002e14,查看所有线程,发现0x00002e14 已经不在了。

3.查找死循环案例

启动windbg 附加MulThrds.exe

1.查看线程运行时间

~*e .ttime;.echo*****

 2.输出线程tid

~*e .echo **********;? @$tid; .ttime;

 3.切换线程

~~[4040]s

 查看堆栈信息:

参考 : 软件调试  ----张银奎

MulThrds.exe 及源码请查看软件调试

http://www.lryc.cn/news/2414103.html

相关文章:

  • Thread out-of-synch 错误
  • 酷炫的网站合集-
  • C++中内存块置0的三种方法:memset, ZeroMemory和SecurZeroMemory
  • vlan的基本配置
  • LEETCODE-DAY27
  • 创建个人网站(一) 如何申请一个网站
  • 电脑蓝屏显示0x000000f4怎么办的四个解决方法
  • Class类的newInstance方法抛出InstantiationException异常
  • js中prompt()的用法
  • C语言socket编程----实现TCP通信
  • 【C语言】常见面笔试题(10道)
  • 全景图像拼接
  • 关于led电源设计
  • c++中静态函数与动态函数的区别
  • 深度学习(四)卷积神经网络-卷积神经网络(3) -Andrew Ng
  • sockaddr和sockaddr_in的区别
  • printf输出格式
  • 167.Web前端网页制作 大气的UI设计平台网页实例 大学生期末大作业
  • Cache(三):cache的常见名词与Cache一致性问题简介
  • mysql安装程序错误代码2503,Win10安装程序错误2502/2503的解决方法
  • CompareNoCase与Compare
  • matlab函数imfilter和 opencv中filter2D函数的对应关系
  • Windows 开机启动 | 启动项管理
  • 在IOS中使用AVPlayer去播放在线音频文件,并设置音量
  • 有道翻译接口逆向_python有道翻译api(2)
  • JSP基于web2.0的超市商品管理系统3sq6z程序+源码+数据库+调试部署+开发环境
  • 【学习资源】C#初学者学习资源推荐
  • Rosetta Tutorial 5/7/9 翻译 | 主要为 Scoring Packer Tutorial 部分
  • MPEG TS流简介
  • 云计算比赛私有云题目