【问题标题】:Windbg, how to read the !locks output?Windbg,如何读取 !locks 输出?
【发布时间】:2014-10-26 13:00:29
【问题描述】:

我正在调试一个我怀疑可能存在死锁或其他多线程相关错误的程序,我按照人们的建议使用 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

我对输出感到困惑,谁能帮忙解释一下?

【问题讨论】:

  • 谢谢,但是每个部分后面的 *** Locked 是什么意思? MS的页面中没有解释。
  • 这意味着CRITICAL_SECTION当前被锁定:)。您可以随时尝试转储您知道 锁定的CRITICAL_SECTION。我希望输出会有所不同
  • !cs -l 将列出相同的内容,但输出可能更好。 !cs -l -o 是我最喜欢的,它还显示了拥有线程的堆栈。

标签: c++ multithreading windbg


【解决方案1】:

!locks 可能会令人困惑。如果您真的想调试死锁情况,请执行 ~*kvn(或您喜欢的 kb)查找等待关键部分的线程,该部分将以 **WaitForSingleForSingleObject 结束,在此之前调用 RtlEnterCriticalSection。找到大多数线程都在关注的关键部分。转储关键部分。如果您正在调试基于 x64 的转储并使用 .frame /c post 缩小到带有 RtlCrticalSection 的帧,则您处于线程上下文 ~[threadnum]s 中,rbx 将包含您的关键部分。

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

希望这会有所帮助。

【讨论】:

  • 谢谢,您能否详细解释一下如何找出线程正在等待的关键部分?
  • 而且我用过~*kvn,每个线程都是这样开头的:Id: 1920.164c Suspend: 0 Teb: 7ef28000 Unfrozen,suspend、teb和unfrozen是什么意思?
  • 真的没有时间登录该网站,我想将不得不进行更多实验,但是以下链接显示了转储 CS blogs.msdn.com/b/ntdebugging/archive/2012/02/28/… 的技术
  • 即使是转储分析选集也有一些模式。 books.google.co.in/…
  • ~*kvn 在内核模式调试中不起作用。有没有好的内核模式替代方案?
【解决方案2】:

Teb 是线程环境块的地址,暂不相关暂停和冻结

假设是 32 位场景,您可以通过以下方式揭示线程正在等待的临界区:

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

(如果 64 遵循上面 Addy 的接收)

【讨论】:

    【解决方案3】:

    要查找由临界区引起的死锁,请尝试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. 
    

    【讨论】:

      【解决方案4】:

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

      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 Processes and Threads number 中查找线程或从命令窗口执行:

      首先,列出所有线程:

      ~*
      

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

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

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

      ~9s
      

      然后您可以查看堆栈并弄清楚发生了什么。在我的例子中,我发现我的线程在持有加载程序锁的同时正在等待一个事件,我们不需要这样做。

      【讨论】:

        猜你喜欢
        • 2019-05-19
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 2011-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-16
        相关资源
        最近更新 更多