C# 使用ReaderWriterLockSlim调试死锁
我正在调试针对.NET3.5的托管应用程序中的挂起。其中一个线程一直在等待方法C# 使用ReaderWriterLockSlim调试死锁,c#,.net,multithreading,debugging,windbg,C#,.net,Multithreading,Debugging,Windbg,我正在调试针对.NET3.5的托管应用程序中的挂起。其中一个线程一直在等待方法System.Threading.ReaderWriterLockSlim.EnterWriteLock。为了找出哪个线程拥有锁,我检查了readerwriterlocksim类以及它包含的所有ReaderWriterCount和RecursiveCounts对象。这些对象包含有关所有线程的信息。包含writercount=0和readercount=0的所有对象,但包含readercount=1的单个对象除外: [5
System.Threading.ReaderWriterLockSlim.EnterWriteLock
。为了找出哪个线程拥有锁,我检查了readerwriterlocksim
类以及它包含的所有ReaderWriterCount
和RecursiveCounts
对象。这些对象包含有关所有线程的信息。包含writercount=0
和readercount=0
的所有对象,但包含readercount=1
的单个对象除外:
[53] 0144fc84
Name: System.Threading.ReaderWriterCount
MethodTable: 6bb4e930
EEClass: 6b9ba4d0
Size: 24(0x18) bytes
(C:\Windows\assembly\GAC_MSIL\System.Core\3.5.0.0__b77a5c561934e089\System.Core.dll)
Fields:
MT Field Offset Type VT Attr Value Name
55782f94 4000625 c System.Int32 1 instance 53 threadid
55782f94 4000626 10 System.Int32 1 instance 1 readercount
6bb4e930 4000627 4 ...ReaderWriterCount 0 instance 00000000 next
6bb4e858 4000628 8 ...g.RecursiveCounts 0 instance 0144fc9c rc
AFAIU表示MTID53的线程拥有锁。我用kb转储了它的堆栈(!clrstack失败,因为它不是托管线程),并得到以下结果:
ChildEBP RetAddr Args to Child
16eee9b4 765c14ab 00000280 00000000 16eee9fc ntdll!ZwWaitForSingleObject+0x15
16eeea20 778d1194 00000280 00009c40 00000000 KERNELBASE!WaitForSingleObjectEx+0x98
16eeea38 681954d7 00000280 00009c40 00000000 KERNEL32!WaitForSingleObjectExImplementation+0x75
16eeea7c 68195423 00000280 00009c40 00000000 mscorwks!PEImage::LoadImage+0x1af
16eeeacc 68195442 00009c40 00000000 00000000 mscorwks!CLREvent::WaitEx+0x117
16eeeae0 681d95c7 00009c40 00000000 00000000 mscorwks!CLREvent::Wait+0x17
16eeeb60 681d9a55 03376058 00009c40 00000000 mscorwks!ThreadpoolMgr::SafeWait+0x73
16eeebc4 68226508 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::WorkerThreadStart+0x11c
16eefa64 778d338a 04b2e5c8 16eefab0 77e09f72 mscorwks!Thread::intermediateThreadProc+0x49
16eefa70 77e09f72 04b2e5c8 6aecf560 00000000 KERNEL32!BaseThreadInitThunk+0xe
16eefab0 77e09f45 682264c2 04b2e5c8 00000000 ntdll!__RtlUserThreadStart+0x70
16eefac8 00000000 682264c2 04b2e5c8 00000000 ntdll!_RtlUserThreadStart+0x1b
也就是说,它是一个
我的第一个想法是,当读卡器锁不总是被释放时,应用程序代码中存在一个bug。但这一假设并未得到证实,因为代码在ReaderWriterLockSlim.EnterWriteLock上使用了包装器,如下所示:
readerWriterLockSlim.EnterReadLock();
try
{
return executeFunc();
}
finally
{
readerWriterLockSlim.ExitReadLock();
}
finally
块必须确保锁始终被释放
有没有想过这种情况是怎么可能的?在锁获取之后,但在最终
之前,线程是否会以某种方式中止,然后成为空闲线程池线程?可能是如何缩小问题范围的提示
另外,这个死锁只被复制了一次,我只有一个内存转储,因此我不能轻易地说在锁周围添加跟踪或断点并进行实验。试试看!sosex.dlk和/或!祝你好运!姆韦茨。这应该会告诉您发生了什么。可能是您遇到了异步异常(如线程中止),从而跳过了最后一块代码。
你可以在“一些限制:可靠性”一节中找到更多关于它的信息。我的实验表明,在重入的情况下,
readercount
等于或大于2
并且锁是递归的。谢谢你的提示。但是这些命令给了我完全相同的信息,我只是用一种更简单的方式描述。一个空闲线程池线程持有一个读锁并阻止继续另一个。抱歉。我更仔细地阅读了你的帖子,这看起来确实很奇怪。您确定您发布的代码段是唯一对此锁具有读锁的代码吗?如果是这样,那么我无法解释这种行为。