我可以使用示例应用程序轻松重现负 LockCount 的影响,以下是我的答案:
对您的问题的答复
关于1)
我应该以 MyModule!RTL_CRITICAL_SECTION 作为明确的线索,这个关键部分可能是在 MyModule 中定义的吗?
是的,这是您对关键部分的定义,它可能与 Microsoft 的定义相对应,也可能不相对应。要使用 Microsoft 的定义,请使用dt nt!_RTL_CRITICAL_SECTION
关于2)
有没有办法让Windbg显示这个临界区的实际变量名? (即假设 #1 为真,并且这是应用程序代码已定义/访问的 CS。)
是的,如果它被调用堆栈上的函数使用。和.frame
,导航到框架,然后使用?? variableName
显示变量,例如
0:000> k L2
# ChildEBP RetAddr
00 0116faa4 00d67419 KERNELBASE!DebugBreak+0x2
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109
0:000> .frame 1
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109 [c:\users\t\documents\visual studio 2015\projects\criticalsectionleavetwice\criticalsectionleavetwice\criticalsectionleavetwice.cpp @ 24]
0:000> ?? CriticalSection
struct _RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0xffffffff _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-2
+0x008 RecursionCount : 0n2
+0x00c OwningThread : 0x00000d6c Void
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0x20007d0
关于3)
为什么上述列表中的 LockCount 值彼此不一致? (一个为 0,另一个为 -2。)
场LockCount
不再是真正的锁定计数,如中所述这个答案 https://stackoverflow.com/a/7408797/480982。相关部分:
在 Microsoft Windows Server 2003 Service Pack 1 及更高版本的 Windows 中,LockCount 字段的解析方式如下:
- 最低位显示锁定状态。如果该位为0,则临界区被锁定;如果为1,则临界区未被锁定。
- 下一位显示是否已为此锁唤醒线程。如果该位为0,则表示已经有一个线程被该锁唤醒;如果为1,则没有线程被唤醒。
- 其余位是等待锁的线程数的反码。
恕我直言!locks
命令应该为你做解释。
的特殊价值-2
is 11111111 ... 1111110
二进制,所以最后一位是0,意味着临界区被锁定。前面的位是1,所以没有线程被唤醒。余数的反码为0,对应锁计数输出!locks
.
这意味着您分析的关键部分不涉及死锁。
关于4)
我想我对 LockCount 有足够的了解,知道它不能低于 -1。更不用说 RecursionCount 似乎与 LockCount 严重不一致。
See #3.
关于未编号的问题5)
我应该把这归因于损坏的CS吗?
不,它似乎没有被损坏。
使用!dlk进行死锁分析
要检查它是否导致死锁,我建议使用sosex /questions/tagged/sosex's (download http://www.stevestechspot.com/default.aspx) !dlk
命令。虽然它主要是 .NET 的扩展,但我曾经请求即使没有 .NET 也能使其适用于关键部分 - 并且该功能是在 SOSex 的较新版本之一中实现的。
如果找不到 .NET,它将输出有关该事实的警告,然后继续分析关键部分:
在你的情况下,它可能看起来像这样:
0:000> !dlk
Unable to initialize .NET data interface. The CLR has not yet been loaded in the process (mscorwks/clr module not loaded).
Examining CriticalSections...
No deadlocks detected.
Usage:
.load c:\path\to\sosex.dll
!dlk
如果它识别出死锁,则非常容易阅读。如果没有,您仍然需要应用其他技术,即不能保证不存在其他类型的死锁(例如,如果等待链包含其他类型的同步对象,如线程、事件等)。
示例输出(不适用于关键部分,但类似):
0:010> !dlk
Deadlock detected:
CLR thread 4 holds sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
waits sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
CLR thread 5 holds sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
waits sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
CLR Thread 4 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
CLR Thread 5 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
1 deadlock detected.
挂分析
!analyze -hang
and 调试诊断 https://www.microsoft.com/en-us/download/details.aspx?id=49924可能有助于挂起分析。