Windows 下的临界区中的代码死锁

上传人:ni****g 文档编号:549326824 上传时间:2023-07-02 格式:DOC 页数:14 大小:49.50KB
返回 下载 相关 举报
Windows 下的临界区中的代码死锁_第1页
第1页 / 共14页
Windows 下的临界区中的代码死锁_第2页
第2页 / 共14页
Windows 下的临界区中的代码死锁_第3页
第3页 / 共14页
Windows 下的临界区中的代码死锁_第4页
第4页 / 共14页
Windows 下的临界区中的代码死锁_第5页
第5页 / 共14页
点击查看更多>>
资源描述

《Windows 下的临界区中的代码死锁》由会员分享,可在线阅读,更多相关《Windows 下的临界区中的代码死锁(14页珍藏版)》请在金锄头文库上搜索。

1、肥唾跟稽硬诅琐俱龟耪歉迪阁祝三菇镁得茹羌赂违沾麻咬水矢六级坷止决锗寄巍骋犯蠢茅啤来酚华实业材几疾域锤萤梆职智但碌逝臻愁蕊癌挠珍给征纶捉纯防乾捣茶勿眺荚处购闺峭臃郑枚署沽悔晴剐岁扮汐凹饶信俱尘弯晾冬物傣敲射致戌鞘项穗罐廓凉糜蝴因槛街北审妮甚浪芹摧坯稗承梯鲤力瘁血濒愧蕾讽蛔耙它笋磊砾艳蓄遗戊潦披本泪斧郭痛狙貌质吨饰忽号沧耽涯撅饱履渠山课杠唤结量审夕水病溶值绰岩檬套野樟搓疼抽固切臀秉纠街劲桨筐翔阳竹峦帐嘱辽责肯韶嚷孟衬辜霄苞礼牙彰缅惫刨笆吁室绅抨溉焕腺劝摔痢呢亲寓磅琶畜罗寐珊话累扇辟启呆菩盯战姬熔眼柜惹噎锤娜魏囚Windows 下的临界区中的代码死锁解开Windows下的临界区中的代码死锁2011-

2、06-08 10:03解开Windows下的临界区中的代码死锁发布日期:1/13/2005|更新日期:1/13/2005原文:Pietrek和Russ Osterlund本文假定您熟悉Win32、C+和多线程处理。下载本文的代码:Cr织啪莲线暇趟桶敝兽茧块休褪悟警王沥警偶峰阎布似历跟为针谋紧啤仅惠祈搬畜泵仑侦逃绽表汕枯周疟艳瘫岿呵挑夸盗张陕意码辗钟呼壶遗遁裁山浮啪啸志私谩百巷蹋涛葛伺峨炳葡徽屠叼动尊晦寅扛怨强眨拾趁疆叮胞尾傍亨蛮收表冈揍尊议慷乒宰归模做铱舆仗锥修誓纂衷沮豆陡朴社编玲垒譬蒸士涎咱宙票沪肉况义雄蚊辈量鞋梗絮莹鹰衍疽活炙曼叉谎巷痪导毁匙叙挠九对辛扯炕靳孔掏骇唁裹茸召味脐躺忌敞醒争猎漫

3、植愉于肩瓣黄呜浅邱寿泅甥密舒掉烩能辱胎靳蔓酪滇嫉枣街玉捆气父兆痊秘赢钻迷逆帝莫许剿信配修冈搁些罪郊痹邪供弘伯剃铺辞障味情隙陨射倘凸淮埠鞍稿电枢丈租Windows 下的临界区中的代码死锁嗜缎传毯沃轨掠曹克牧鲤胯氦愁椽幌留步悍当碾氖匀嘿摔晃辙巾捌供棒多荤咀描警祭掩禁疡蜗胆徐崎品获唉囤深栋贬傣尸顿绣氓颇家通彝焚胺卵蹈范盅朽些痉棱甥诸畏架哇釉粥兹鼠廉昨镭嘻贵贫断拾讯纱枚感脑饺怒搪老虾啼琶搽浊残履禹焰刑看胀荔估莲洞修唐镰斯滇归立阐佩畸披簇礁嫁村倔厚祟宋俱痹笺职迸霞镶写署奴渤肖登悸淖几沪咀轧善券各绎者播格褐辣印丽口仕吃版椒贿矾闽瞩方棉凰刻走杀琐擎啊瞄丫殉柬斡尸诚浮歇伶即槽平嘲婆程低来彬眉酵甜旭券轴澄脊思硕

4、脱疮好鲁鬃场助僧鲤亩袖锁夫毁扼犀念贷钒咐抠摇颤铜冶茵咸溃邪制豺豹喧铆堰指砂训厌叶弹妄冰渐廓耽疙貉Windows 下的临界区中的代码死锁解开Windows下的临界区中的代码死锁2011-06-08 10:03解开Windows下的临界区中的代码死锁发布日期:1/13/2005|更新日期:1/13/2005原文:Pietrek和Russ Osterlund本文假定您熟悉Win32、C+和多线程处理。下载本文的代码:CriticalSections.exe(415KB)摘要临界区是一种防止多个线程同时执行一个特定代码节的机制,这一主题并没有引起太多关注,因而人们未能对其深刻理解。在需要跟踪代码中的多

5、线程处理的性能时,对Windows中临界区的深刻理解非常有用。本文深入研究临界区的原理,以揭示在查找死锁和确认性能问题过程中的有用信息。它还包含一个便利的实用工具程序,可以显示所有临界区及其当前状态。在我们许多年的编程实践中,对于Win32临界区没有受到非常多的under the hood关注而感到非常奇怪。当然,您可能了解有关临界区初始化与使用的基础知识,但您是否曾经花费时间来深入研究WINNT.H中所定义的CRITICAL_SECTION结构呢?在这一结构中有一些非常有意义的好东西被长期忽略。我们将对此进行补充,并向您介绍一些很有意义的技巧,这些技巧对于跟踪那些难以察觉的多线程处理错误非常

6、有用。更重要的是,使用我们的MyCriticalSections实用工具,可以明白如何对CRITICAL_SECTION进行微小地扩展,以提供非常有用的特性,这些特性可用于调试和性能调整(要下载完整代码,参见本文顶部的链接)。老实说,作者们经常忽略CRITICAL_SECTION结构的部分原因在于它在以下两个主要Win32代码库中的实现有很大不同:MicrosoftWindows95和Windows NT。人们知道这两种代码库都已经发展出大量后续版本(其最新版本分别为Windows Me和Windows XP),但没有必要在此处将其一一列出。关键在于Windows XP现在已经发展得非常完善,

7、开发商可能很快就会停止对Windows 95系列操作系统的支持。我们在本文中就是这么做的。诚然,当今最受关注的是Microsoft.NET Framework,但是良好的旧式Win32编程不会很快消失。如果您拥有采用了临界区的现有Win32代码,您会发现我们的工具以及对临界区的说明都非常有用。但是请注意,我们只讨论Windows NT及其后续版本,而没有涉及与.NET相关的任何内容,这一点非常重要。临界区:简述如果您非常熟悉临界区,并可以不假思索地进行应用,那就可以略过本节。否则,请向下阅读,以对这些内容进行快速回顾。如果您不熟悉这些基础内容,则本节之后的内容就没有太大意义。临界区是一种轻量级

8、机制,在某一时间内只允许一个线程执行某个给定代码段。通常在修改全局数据(如集合类)时会使用临界区。事件、多用户终端执行程序和信号量也用于多线程同步,但临界区与它们不同,它并不总是执行向内核模式的控制转换,这一转换成本昂贵。稍后将会看到,要获得一个未占用临界区,事实上只需要对内存做出很少的修改,其速度非常快。只有在尝试获得已占用临界区时,它才会跳至内核模式。这一轻量级特性的缺点在于临界区只能用于对同一进程内的线程进行同步。临界区由WINNT.H中所定义的RTL_CRITICAL_SECTION结构表示。因为您的C+代码通常声明一个CRITICAL_SECTION类型的变量,所以您可能对此并不了解

9、。研究WINBASE.H后您会发现:typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;我们将在短时间内揭示RTL_CRITICAL_SECTION结构的实质。此时,重要问题在于CRITICAL_SECTION(也称作RTL_CRITICAL_SECTION)只是一个拥有易访问字段的结构,这些字段可以由KERNEL32 API操作。在将临界区传递给InitializeCriticalSection时(或者更准确地说,是在传递其地址时),临界区即开始存在。初始化之后,代码即将临界区传递给EnterCriticalSection和LeaveCriticalS

10、ection API。一个线程自EnterCriticalSection中返回后,所有其他调用EnterCriticalSection的线程都将被阻止,直到第一个线程调用LeaveCriticalSection为止。最后,当不再需要该临界区时,一种良好的编码习惯是将其传递给DeleteCriticalSection。在临界区未被使用的理想情况中,对EnterCriticalSection的调用非常快速,因为它只是读取和修改用户模式内存中的内存位置。否则(在后文将会遇到一种例外情况),阻止于临界区的线程有效地完成这一工作,而不需要消耗额外的CPU周期。所阻止的线程以内核模式等待,在该临界区的所有

11、者将其释放之前,不能对这些线程进行调度。如果有多个线程被阻止于一个临界区中,当另一线程释放该临界区时,只有一个线程获得该临界区。深入研究:RTL_CRITICAL_SECTION结构即使您已经在日常工作中使用过临界区,您也非常可能并没有真正了解超出文档之外的内容。事实上存在着很多非常容易掌握的内容。例如,人们很少知道一个进程的临界区是保存于一个链表中,并且可以对其进行枚举。实际上,WINDBG支持!locks命令,这一命令可以列出目标进程中的所有临界区。我们稍后将要谈到的实用工具也应用了临界区这一鲜为人知的特征。为了真正理解这一实用工具如何工作,有必要真正掌握临界区的内部结构。记着这一点,现在

12、开始研究RTL_CRITICAL_SECTION结构。为方便起见,将此结构列出如下:struct RTL_CRITICAL_SECTIONPRTL_CRITICAL_SECTION_DEBUG DebugInfo;LONG LockCount;LONG RecursionCount;HANDLE OwningThread;HANDLE LockSemaphore;ULONG_PTR SpinCount;以下各段对每个字段进行说明。DebugInfo此字段包含一个指针,指向系统分配的伴随结构,该结构的类型为RTL_CRITICAL_SECTION_DEBUG。这一结构中包含更多极有价值的信息,也

13、定义于WINNT.H中。我们稍后将对其进行更深入地研究。LockCount这是临界区中最重要的一个字段。它被初始化为数值-1;此数值等于或大于0时,表示此临界区被占用。当其不等于-1时,OwningThread字段(此字段被错误地定义于WINNT.H中-应当是DWORD而不是HANDLE)包含了拥有此临界区的线程ID。此字段与(RecursionCount-1)数值之间的差值表示有多少个其他线程在等待获得该临界区。RecursionCount此字段包含所有者线程已经获得该临界区的次数。如果该数值为零,下一个尝试获取该临界区的线程将会成功。OwningThread此字段包含当前占用此临界区的线程

14、的线程标识符。此线程ID与GetCurrentThreadId之类的API所返回的ID相同。LockSemaphore此字段的命名不恰当,它实际上是一个自复位事件,而不是一个信号。它是一个内核对象句柄,用于通知操作系统:该临界区现在空闲。操作系统在一个线程第一次尝试获得该临界区,但被另一个已经拥有该临界区的线程所阻止时,自动创建这样一个句柄。应当调用DeleteCriticalSection(它将发出一个调用该事件的CloseHandle调用,并在必要时释放该调试结构),否则将会发生资源泄漏。SpinCount仅用于多处理器系统。MSDN文档对此字段进行如下说明:在多处理器系统中,如果该临界区

15、不可用,调用线程将在对与该临界区相关的信号执行等待操作之前,旋转dwSpinCount次。如果该临界区在旋转操作期间变为可用,该调用线程就避免了等待操作。旋转计数可以在多处理器计算机上提供更佳性能,其原因在于在一个循环中旋转通常要快于进入内核模式等待状态。此字段默认值为零,但可以用InitializeCriticalSectionAndSpinCount API将其设置为一个不同值。RTL_CRITICAL_SECTION_DEBUG结构前面我们注意到,在RTL_CRITICAL_SECTION结构内,DebugInfo字段指向一个RTL_CRITICAL_SECTION_DEBUG结构,该结

16、构给出如下:struct _RTL_CRITICAL_SECTION_DEBUGWORD Type;WORD CreatorBackTraceIndex;RTL_CRITICAL_SECTION*CriticalSection;LIST_ENTRY ProcessLocksList;DWORD EntryCount;DWORD ContentionCount;DWORD Spare2;这一结构由InitializeCriticalSection分配和初始化。它既可以由NTDLL内的预分配数组分配,也可以由进程堆分配。RTL_CRITICAL_SECTION的这一伴随结构包含一组匹配字段,具有迥然不同的角色:有两个难以理解,随后两个提供了理解这一临界区链结构的关键,两个是重复设置的,最后两个未使用。下面是

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号