我正在调试一个程序,我怀疑可能存在死锁或其他与线程相关的错误,我按照人们的建议使用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
我对输出感到困惑,有人可以帮忙解释一下吗?
答案 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的容器)
答案 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
然后您可以查看堆栈并弄清楚发生了什么。就我而言,我发现我的线程在按住加载程序锁的同时正在等待事件,而我们不必这样做。