Windbg,怎么读!锁输出?

时间:2014-10-26 13:00:30

标签: c++ multithreading windbg

我正在调试一个程序,我怀疑可能存在死锁或其他与线程相关的错误,我按照人们的建议使用WinDBG打开故障转储文件并使用!locks来获取以下输出:

CritSec MSVCR100D!lclcritsects+48 at 73541e40
WaiterWoken        No
LockCount          6
RecursionCount     1
OwningThread       164c
EntryCount         0
ContentionCount    9
*** Locked

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for qsqlited4.dll - 
CritSec qsqlited4!qt_plugin_instance+a1b21 at 70fc301c
WaiterWoken        No
LockCount          0
RecursionCount     1
OwningThread       2344
EntryCount         0
ContentionCount    0
*** Locked

CritSec +73c2380 at 073c2380
WaiterWoken        No
LockCount          0
RecursionCount     4
OwningThread       2344
EntryCount         0
ContentionCount    0
*** Locked

CritSec +73bf9e8 at 073bf9e8
WaiterWoken        No
LockCount          0
RecursionCount     1
OwningThread       2344
EntryCount         0
ContentionCount    0    
*** Locked

Scanned 817 critical sections

我对输出感到困惑,有人可以帮忙解释一下吗?

4 个答案:

答案 0 :(得分:9)

!锁可能令人困惑。如果你真的想要调试死锁情况,那么做一个〜* kvn(或者你喜欢的kb)找到等待关键部分的线程,这些部分将以** WaitForSingleForSingleObject结束,然后在RtlEnterCriticalSection调用之前。找到大多数线程正在关注的关键部分。转储关键部分。如果你正在调试基于x64的转储,并使用.frame / c post缩小到携带RtlCrticalSection的帧,你在线程上下文〜[threadnum] s中,rbx将包含你的关键部分。

转储关键部分找到所有者。如果主人正在等待找到所有者等待的东西等等,直到我们到达链的末端或事情被阻止的原因。 !如果我们不将它放在上下文中,cs -l -o可能会令人困惑。

希望这会有所帮助。

答案 1 :(得分:3)

Teb是线程环境块的地址,Suspend&冻结现在不相关

假设它是32位场景,您可以显示线程正在等待的哪个关键部分:

a) Switch to the thread
b) dump stack
c) Find 1 argument to RtlEnterCriticalSection

(如果64跟随上面Addy的容器)

enter image description here

答案 2 :(得分:1)

要查找关键部分导致的死锁,请尝试使用SOSEX' !dlk命令。尽管扩展似乎仅适用于.NET,但!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. 

答案 3 :(得分:0)

从样本输出中显示的第一个锁开始,这就是我对如何解释信息的理解:

CritSec MSVCR100D!lclcritsects+48 at 73541e40 - address of the lock
WaiterWoken        No - unclear, ignore
LockCount          6 - how many threads are waiting to acquire the lock
RecursionCount     1 - how many times the owner thread has acquired the lock
OwningThread       164c - the thread ID of the owner, in hex
EntryCount         0 - obsolete?
ContentionCount    9 - the highest LockCount value seen
*** Locked - this indicates that the critical is currently held

因此,我们可以看到线程164c拥有该锁,但不是递归的。有六个线程正在等待获取锁。在过去的某个时候,有九个线程试图获取该锁。

可能您想做的是切换到拥有线程,并查看它在做什么,为什么它仍持有该锁,等等。您可以在windbg进程和线程号中查找该线程,或者在命令窗口中进行操作:

首先,列出所有线程:

~*

然后,找到感兴趣的线程,查找感兴趣的线程ID,然后切换到该线程。例如,您可能会找到以下输出:

9  Id: 15b8.164c Suspend: 0 Teb: fffa4000 Unfrozen
   Priority: 10

9是线程号15b8.164c是进程ID和线程ID。由于您要查找的是164c,这意味着感兴趣的线程是9号,因此您可以发出以下命令:

~9s

然后您可以查看堆栈并弄清楚发生了什么。就我而言,我发现我的线程在按住加载程序锁的同时正在等待事件,而我们不必这样做。