如何找到死锁?

How to find a deadlock?

我正在尝试按照 this Microsoft link 中解释的程序查找我的应用程序中可能存在的死锁。

在我的例子中,我也从函数 !locks:

开始
CritSec +1130780 at 01130780
WaiterWoken        No
LockCount          0
RecursionCount     1
OwningThread       1624
EntryCount         0
ContentionCount    8
*** Locked

CritSec Wldap32!SelectLock1+0 at 7630a1b0
WaiterWoken        No
LockCount          1
RecursionCount     1
OwningThread       30d8
EntryCount         0
ContentionCount    219
*** Locked

CritSec Wldap32!SelectLock2+0 at 7630a168
WaiterWoken        No
LockCount          0
RecursionCount     1
OwningThread       1624
EntryCount         0
ContentionCount    47d
*** Locked

CritSec +cd6838 at 00cd6838
WaiterWoken        No
LockCount          1
RecursionCount     1
OwningThread       4584
EntryCount         0
ContentionCount    184
*** Locked

Scanned 107 critical sections

第二项提到我需要去线程30d8:

0:000> ~
...
  59  Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
...

因此,我可能希望获得有关线程 59 中关键部分的信息,但在查看时:

  59  Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
 # ChildEBP RetAddr  Args to Child              
00 0a48f4c4 74de9220 000036b8 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
01 0a48f574 74df376d 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2Ex+0x208
02 0a48f5ac 74df37a7 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2+0x2d
03 0a48f5e0 76303545 0d7acba0 bdd2500a 0a48f61f IPHLPAPI!IcmpSendEcho+0x27
04 0a48f6c0 762e0a46 0a48f79c 0c2180a0 0a08d660 Wldap32!LdapPingServer+0xa1
05 0a48f708 762c4ca0 00001363 0c3f2ba0 00000000 Wldap32!DrainWinsock+0x1c69a
06 0a48f778 762c6eae 00002774 00000000 0a48f79c Wldap32!LdapWaitForResponseFromServer+0x767
07 0a48f7d0 762c7bf9 00000000 0a48f850 0a48f9d4 Wldap32!ldap_result_with_error+0xf2
08 0a48f7f8 002c3a9b 0a08d88c 00001363 00000000 Wldap32!ldap_result+0x59
09 0a48faf8 002bcc1e 04059930 569939a1 00c21220 <Application>!CActiveDirectoryInfo::LDAPNotificationFunc+0xe5b
0a 0a48fb24 002c41a0 04059930 569939e5 7437f28e <Application>!CActiveDirectoryInfo::LDAPNotification_Protected+0xbe
0b 0a48fb60 7437f2e9 04059930 22a3f765 7437f28e <Application>!LDAPNotification+0x50
0c 0a48fb98 7437f2cd 7437f28e 0a48fbb8 75547c04 msvcr110!_beginthreadex+0xb4
0d 0a48fba4 75547c04 026f2b28 75547be0 238314af msvcr110!_endthreadex+0x102
0e 0a48fbb8 77d9ad2f 026f2b28 21045533 00000000 kernel32!BaseThreadInitThunk+0x24
0f 0a48fc00 77d9acfa ffffffff 77d800c7 00000000 ntdll!__RtlUserThreadStart+0x2f
10 0a48fc10 00000000 7437f28e 026f2b28 00000000 ntdll!_RtlUserThreadStart+0x1b

第一条评论后编辑:

不幸的是,命令 sosex.dlk 没有显示任何信息,即使在 运行 !bhi 命令之后也是如此。

就调查36b8而言,也没有太多信息:

0:000> !handle 36b8 f
Handle 000036b8
  Type          Event
  Attributes    0
  GrantedAccess 0x1f0003:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState,ModifyState
  HandleCount   2
  PointerCount  65538
  Name          <none>
  Object specific information
    Event Type Auto Reset
    Event is Waiting

我不知道 !findstack 功能,你能告诉我我做错了什么吗?

0:000> !findstack CriticalSection
0:000> !findstack *!CriticalSection
0:000> !findstack RtlEnterCriticalSection
0:000> !findstack *CriticalSection*
=> always no results.

线程 59 已经拥有临界区。这意味着它在前一段时间调用了 EnterCriticalSection。您将不会再在调试器中看到它。该线程 应该 在某个时候调用 LeaveCriticalSection。但目前它正在等待其他事情发生(WaitForSingleObject on object 36b8)。

后续步骤:

  • 找出 36b8 是什么,使用 !handle 36b8 f
  • 与 59 不同的线程可能正在该临界区等待。所以当心 EnterCriticalSection 使用 !findstack.

如果您怀疑死锁只是由临界区引起的,您可以使用!sosex.dlk。虽然 SOSEX 是为 .NET 死锁设计的,但它也可以检测关键部分的死锁。

您应该考虑关闭 ldap 连接对象上的 ping。如果您正在调用此调用堆栈,则通常意味着 ICMP/ping 在您的域控制器和调用应用程序服务器之间不起作用(您可以使用应用程序服务器的 ping 命令行工具对此进行测试;如果该工具挂起或超时,您的挂起与应用程序相同。

如果您不拥有进行底层 ldap 调用的库,则应将您的网络设置为允许或拒绝 ping,而不是丢弃它们。