我有一个由c++编写的程序,我很难找到哪个线程已经获得了Slim阅读器/作家(SRW)锁。我搜索并找到了确定保存ReaderWriterLockSlim WriteLock的方法,但它是关于C#编写的一个程序的。此外,一些命令,例如.rwlock
,是不可接受的。
0:796> !handle 0 ff Mutant
Handle c
Type Mutant
Attributes 0
GrantedAccess 0x1f0001:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState
HandleCount 4
PointerCount 103240
Name \BaseNamedObjects\DBWinMutex
Object Specific Information
Mutex is Free
Handle 474
Type Mutant
Attributes 0
GrantedAccess 0x1f0001:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState
HandleCount 2
PointerCount 65536
Name \BaseNamedObjects\SM0:928:304:WilStaging_02
Object Specific Information
Mutex is Free
2 handles of type Mutant
0:796> kb
RetAddr : Args to Child : Call Site
00007ff9`b6e3d33a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForAlertByThreadId+0x14
00007ff9`a85726a9 : 00000000`00000000 00000000`00000000 00000192`83338180 00000000`00000000 : ntdll!RtlAcquireSRWLockExclusive+0x13a
00007ff9`a6231724 : c000000d`00000000 00000000`00000000 00000192`83338180 00000000`00000002 : MSVCP140!mtx_do_lock+0x7d [d:\agent\_work\2\s\src\vctools\crt\crtw32\stdcpp\thr\mutex.cpp @ 106]
00007ff9`a626749e : 00000192`f6a26e38 00000193`4aaa3d80 00000052`897fea60 00000000`00000000 : AZSDK!AZConnection::Post+0x54 [g:\prod\sdk\src\connection.cpp @ 1147]
...
00007ff9`9c8ba9c1 : 00000192`c3b3d770 00000000`00000000 00000192`f5d616b0 00000000`00000000 : prod!Task::Execute+0x28 [g:\prod\src\task.cpp @ 51]
00007ff9`b6e97529 : 00000193`491b9830 00000000`7ffe0386 00000052`897ff998 00000193`491b98f8 : prod!Proxy::TaskExecuter+0x11 [g:\prod\src\proxy.cpp @ 2042]
00007ff9`b6e3bec4 : 00000000`00000000 00000192`f1dd03a0 00000000`00000000 00000000`00000000 : ntdll!TppSimplepExecuteCallback+0x99
00007ff9`b6c47e94 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!TppWorkerThread+0x644
00007ff9`b6e87ad1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
0:796> !rwlock
No export rwlock found
C++代码片段:
std::mutex m_mutex;
Status AZConnection::Post(const Request* request, Result** pResult)
{
std::lock_guard<std::mutex> sbguard(m_mutex);
}
更新:
根据鲁斯特克斯的回答的说法,我明白了。现在我必须放弃。
事实上,我的程序还在运行,但已经停止使用了。我得找出原因。我发现有806个线程,其中大多数都在焦急地等待Post
。此外,如果它不能再现,我不能重新开始添加一个日志打印谁已经获得了锁。因此,我只想检查持有锁的线程正在执行什么操作。
发布于 2020-04-01 15:05:32
我可以使用!foreachframe
和!if
在WinDbg的MEX调试扩展中对调用堆栈进行grep,并执行一个命令(不支持由;;(指挥分离员)分隔的多个命令),以查找不是为锁而瓦特但其上一次调用为Post
的线程。扩展可以从这里下载。下载后,可以将其放入C:\WinDDK\7600.16385.1\Debuggers\winext
(也请参阅加载调试器扩展DLL)。
在下面的代码中,我用msvcrt!_threadstartex
替换了msvcrt!_threadstartex
,用KERNEL32!BaseThreadInitThunk
替换了AZSDK!AZConnection::Post
,举个例子:
~*e r @$t0 = -1; !foreachframe -q -f 'KERNEL32!BaseThreadInitThunk' r @$t0= @#FrameNum - 1; .if(0<=@$t0) { !if -DoesNotContainRegex 'msvcrt!_threadstartex' -then '.printf /D "Thread: <link cmd=\"~~[%x]\">0x%x</link> (<link cmd=\"!mex.t %d\">%d</link>)", $tid, $tid, $dtid, $dtid' .frame @$t0 }
!foreachthread -q !foreachframe -q -f 'KERNEL32!BaseThreadInitThunk' !if -DoesNotContainRegex 'msvcrt!_threadstartex' -then '.printf /D "Thread: <link cmd=\"~~[%x]\">0x%x</link> (<link cmd=\"!mex.t %d\">%d</link>)", $tid, $tid, $dtid, $dtid' .frame @#FrameNum - 1
它用于notepad
进程的输出示例:
Thread: 0xd14c (0)
Thread: 0x4f88 (1)
Thread: 0xd198 (7)
所有线程的调用堆栈
0:001> !foreachthread k
Child-SP RetAddr Call Site
00000062`fabaf8c8 00007ffd`54c7409d win32u!ZwUserGetMessage+0x14
00000062`fabaf8d0 00007ff7`bb4c449f USER32!GetMessageW+0x2d
00000062`fabaf930 00007ff7`bb4dae07 notepad+0x449f
00000062`fabafa30 00007ffd`570f7974 notepad+0x1ae07
00000062`fabafaf0 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fabafb20 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Changing to thread: 0xda94 (1)
Child-SP RetAddr Call Site
00000062`fae7fbc8 00007ffd`5847f01b ntdll!DbgBreakPoint
00000062`fae7fbd0 00007ffd`570f7974 ntdll!DbgUiRemoteBreakin+0x4b
00000062`fae7fc00 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fae7fc30 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Changing to thread: 0xdb60 (7)
Child-SP RetAddr Call Site
00000062`fb17f968 00007ffd`54c7004d win32u!ZwUserMsgWaitForMultipleObjectsEx+0x14
00000062`fb17f970 00007ffc`e4e7d078 USER32!MsgWaitForMultipleObjectsEx+0x9d
00000062`fb17f9b0 00007ffc`e4e7cec2 DUser!GetMessageExA+0x2f8
00000062`fb17fa50 00007ffd`54c77004 DUser!GetMessageExA+0x142
00000062`fb17fab0 00007ffd`584534a4 USER32!Ordinal2582+0x64
00000062`fb17fb50 00007ffd`54101164 ntdll!KiUserCallbackDispatcher+0x24
00000062`fb17fbc8 00007ffd`54c7409d win32u!ZwUserGetMessage+0x14
00000062`fb17fbd0 00007ffd`2e4efa3c USER32!GetMessageW+0x2d
00000062`fb17fc30 00007ffd`1d0b30f8 DUI70!StartMessagePump+0x3c
00000062`fb17fc90 00007ffd`1d0b31ce msctfuimanager!DllCanUnloadNow+0xf3e8
00000062`fb17fd50 00007ffd`570f7974 msctfuimanager!DllCanUnloadNow+0xf4be
00000062`fb17fd80 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fb17fdb0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Changing to thread: 0xc490 (8)
Child-SP RetAddr Call Site
00000062`fb1ff708 00007ffd`54c7004d win32u!ZwUserMsgWaitForMultipleObjectsEx+0x14
00000062`fb1ff710 00007ffc`e4e7d1ca USER32!MsgWaitForMultipleObjectsEx+0x9d
00000062`fb1ff750 00007ffc`e4e7cde7 DUser!GetMessageExA+0x44a
00000062`fb1ff7f0 00007ffc`e4e7ca53 DUser!GetMessageExA+0x67
00000062`fb1ff840 00007ffd`5505b0ea DUser!GetGadgetFocus+0x33b3
00000062`fb1ff8d0 00007ffd`5505b1bc msvcrt!_callthreadstartex+0x1e
00000062`fb1ff900 00007ffd`570f7974 msvcrt!_threadstartex+0x7c
00000062`fb1ff930 00007ffd`5841a261 KERNEL32!BaseThreadInitThunk+0x14
00000062`fb1ff960 00000000`00000000 ntdll!RtlUserThreadStart+0x21
更新:
我发现有人也有同样的想法(如果链接是死气沉沉的,经常发生):
超薄的读写器锁不记得主人是谁,所以你必须用其他方式找到它们 2011年8月10日 超薄读写器锁是一种非常方便的同步工具,但缺点之一是它不>跟踪当前所有者是谁。 当您的线程被困在等待获得一个苗条的读取器/写入器锁时,需要知道的一件自然的事情是,哪些线程拥有被卡住的线程>等待的资源。 由于没有从等待线程转到拥有线程的功能,所以您只需要以其他方式找到拥有的线程。下面是在共享模式下等待锁的线程>: ntdll!ZwWaitForKeyedEvent+0xc ntdll!RtlAcquireSRWLockShared+0x126 dbquery!CSearchSpace::Validate+0x10b dbquery!CQuery::AddConfigs+0xdc dbquery!CQuery::ResolveProviders+0x89 dbquery!CResults::CreateProviders+0x85 dbquery!CResults::GetProviders+0x61 dbquery!CResults::CreateResults+0x11c 好吧,你是怎么找到锁的线程的? 首先,苗条的读取器/写入器锁只能在进程中使用,因此候选线程是进程中的线程。 其次,锁的使用模式几乎总是类似于 进入锁,做一些出口锁 对于一个函数来说,取一个锁并退出到 持有锁的外部代码。(它可能退出到同一组件中的其他代码,将退出锁的义务转移到该其他代码。) 因此,您希望查找仍然在
dbquery.dll
中的线程,甚至可能仍然在CSearchSpace
中(如果锁是每个对象的锁,而不是全局锁)。 当然,可能是进入锁的代码搞砸了,忘记了释放它,但如果是这样的话,搜索它的数量就不会>找到任何东西,因为罪魁祸首早就消失了。 既然是调试是一项乐观的练习。,我们也可以假设“我们不是这种情况”。如果它找不到锁所有者,那么我们可能不得不重新考虑这个假设。 最后,最后一个诀窍是了解哪些线程要忽略?。现在,您还可以忽略等待锁的线程,因为它们是受害者,而不是原因。(同样,如果我们找不到锁所有者,我们>可以重新考虑它们不是原因的假设;例如,他们可能试图递归地获取锁。) 碰巧, 进程中只有一个线程可以传递所有上述过滤器。 dbquery!CProp::Marshall+0x3b dbquery!CRequest::CRequest+0x24c dbquery!CQuery::Execute+0x668 dbquery!CResults::FillParams+0x1c4 dbquery!CResults::AddProvider+0x4e dbquery!CResults::AddConfigs+0x1c5 dbquery!CResults::CreateResults+0x145 这可能不是问题的根源,但这是一个好的开始。 (实际上,它看上去很有希望,因为问题可能是 (封送处理程序的另一端的进程被卡住了。)
https://stackoverflow.com/questions/60947806
复制相似问题