欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NET线程同步问题的调试方法

程序员文章站 2022-09-02 22:34:08
问题介绍 .NET中线程同步经常用到以下方式, lock statement AutoResetEvent/MannualResetEvent Mutex Semapho...

问题介绍
.NET中线程同步经常用到以下方式,
lock statement
AutoResetEvent/MannualResetEvent
Mutex
Semaphore
ReaderWriterLock
Interlocked
线程同步经常遇到的问题有以下几种,
等待 - 等待锁释放
死锁 - 请求锁资源顺序不一致而造成互锁
脏读 - 线程访问资源缺少同步机制保护
死锁也是等待,只是死锁的等待程序无法自解。

.NET线程同步问题的调试方法
脏读一般用在数据库系统中的概念,即多个线程访问同一个资源过程中读与写同时进行。例如在循环遍历某个数组的时候抛出了异常报告正在遍历的数组被更改,Collection was modified; enumeration operation may not execute..NET线程同步问题的调试方法

这类问题造成的原因主要是由于在写的过程中缺少排他锁,相应的解决方案可以考虑减少资源的可见度,把资源的访问控制在有限的几个特定的方法中,然后在这些特定的方法上面相应的读写处加锁来避免脏读发生。

调试方法

lock statement
调试等待问题首先还是要先确定线程对象,弄清楚谁在等谁?下面是一个使用lock statement (Monitor class)的简单线程等待的例子,3号线程在Sleep,4号线程在等待。根据调用栈我们可以知道四号线程是在调用Monitor.Enter()方法。
   3  Id: 27fc.7f0 Suspend: 1 Teb: 000007f5`ffae6000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`1b9fea28 000007f8`0e6b11f2 ntdll!NtDelayExecution+0xa
00000000`1b9fea30 000007ff`f803369d KERNELBASE!SleepEx+0xaa
00000000`1b9fead0 000007ff`f7c2e7fd mscorwks!EESleepEx+0x2d
00000000`1b9feb50 000007ff`f81f0769 mscorwks!Thread::UserSleep+0x71
00000000`1b9febb0 000007ff`98500486 mscorwks!ThreadNative::Sleep+0xf9
00000000`1b9fed60 000007ff`f30d2bdb Synchronization!Synchronization.Program.ThreadProc()+0x106
00000000`1b9fee00 000007ff`f316a9bd mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x9b
00000000`1b9fee50 000007ff`f7dbd552 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+0x4d
00000000`1b9feea0 000007ff`f7cfa283 mscorwks!CallDescrWorker+0x82
00000000`1b9feef0 000007ff`f819c7af mscorwks!CallDescrWorkerWithHandler+0xd3
00000000`1b9fef90 000007ff`f7be4415 mscorwks!MethodDesc::CallDescr+0x2af
00000000`1b9ff1d0 000007ff`f7d3cda4 mscorwks!ThreadNative::KickOffThread_Worker+0x191
00000000`1b9ff4f0 000007ff`f7d23721 mscorwks!ManagedThreadBase_DispatchInner+0x2c
00000000`1b9ff540 000007ff`f7c1fc59 mscorwks!ManagedThreadBase_DispatchMiddle+0x9d
00000000`1b9ff610 000007ff`f7d7c949 mscorwks!ManagedThreadBase_DispatchOuter+0x31
00000000`1b9ff650 000007ff`f7d472d3 mscorwks!ManagedThreadBase_FullTransitionWithAD+0x35
00000000`1b9ff6b0 000007ff`f7d3f3a4 mscorwks!ThreadNative::KickOffThread+0xd3
00000000`1b9ff790 000007f8`0f16167e mscorwks!Thread::intermediateThreadProc+0x78
00000000`1b9ff8e0 000007f8`116d3501 KERNEL32!BaseThreadInitThunk+0x1a
00000000`1b9ff910 00000000`00000000 ntdll!RtlUserThreadStart+0x21

   4  Id: 27fc.2634 Suspend: 1 Teb: 000007f5`ffae4000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`1bafe5c8 000007f8`0e6b12c6 ntdll!ZwWaitForMultipleObjects+0xa
00000000`1bafe5d0 000007ff`f7c1e7f9 KERNELBASE!WaitForMultipleObjectsEx+0xe5
00000000`1bafe8b0 000007ff`f7c231e1 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0xc1
00000000`1bafe950 000007ff`f7d203d5 mscorwks!Thread::DoAppropriateAptStateWait+0x41
00000000`1bafe9b0 000007ff`f7c3e94c mscorwks!Thread::DoAppropriateWaitWorker+0x191
00000000`1bafeab0 000007ff`f7c7d16a mscorwks!Thread::DoAppropriateWait+0x5c
00000000`1bafeb20 000007ff`f7c00fd1 mscorwks!CLREvent::WaitEx+0xbe
00000000`1bafebd0 000007ff`f7d4e002 mscorwks!AwareLock::EnterEpilog+0xc9
00000000`1bafeca0 000007ff`f815a815 mscorwks!AwareLock::Enter+0x72
00000000`1bafecd0 000007ff`98500427 mscorwks!JIT_MonEnterWorker_Portable+0xf5
00000000`1bafeea0 000007ff`f30d2bdb Synchronization!Synchronization.Program.ThreadProc()+0xa7
00000000`1bafef40 000007ff`f316a9bd mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x9b
00000000`1bafef90 000007ff`f7dbd552 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+0x4d
00000000`1bafefe0 000007ff`f7cfa283 mscorwks!CallDescrWorker+0x82
00000000`1baff030 000007ff`f819c7af mscorwks!CallDescrWorkerWithHandler+0xd3
00000000`1baff0d0 000007ff`f7be4415 mscorwks!MethodDesc::CallDescr+0x2af
00000000`1baff310 000007ff`f7d3cda4 mscorwks!ThreadNative::KickOffThread_Worker+0x191
00000000`1baff630 000007ff`f7d23721 mscorwks!ManagedThreadBase_DispatchInner+0x2c
00000000`1baff680 000007ff`f7c1fc59 mscorwks!ManagedThreadBase_DispatchMiddle+0x9d
00000000`1baff750 000007ff`f7d7c949 mscorwks!ManagedThreadBase_DispatchOuter+0x31
00000000`1baff790 000007ff`f7d472d3 mscorwks!ManagedThreadBase_FullTransitionWithAD+0x35
00000000`1baff7f0 000007ff`f7d3f3a4 mscorwks!ThreadNative::KickOffThread+0xd3
00000000`1baff8d0 000007f8`0f16167e mscorwks!Thread::intermediateThreadProc+0x78
00000000`1baffaa0 000007f8`116d3501 KERNEL32!BaseThreadInitThunk+0x1a
00000000`1baffad0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

由于Monitor.Enter涉及到一个同步对象,我们可以尝试找一下这个同步对象,在本地变量里面找到一个object,
0:004> !clrstack -a
OS Thread Id: 0x2634 (4)
Child-SP         RetAddr          Call Site
000000001bafeea0 000007fff30d2bdb Synchronization.Program.ThreadProc()
    PARAMETERS:
        this = 0x0000000003023bf0
    LOCALS:
        0x000000001bafeec8 = 0x0000000003023c08

000000001bafef40 000007fff316a9bd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    PARAMETERS:
        executionContext = <no data>
        callback = <no data>
        state = <no data>
    LOCALS:
        <no data>
0:004> !do 0x0000000003023c08
Name: System.Object
MethodTable: 000007fff3217510
EEClass: 000007fff2de2200
Size: 24(0x18) bytes
 (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Object
Fields:
None

注意object地址-4为对象同步块地址。

0:004> dd 0x0000000003023c08-4 l1
00000000`03023c04  08000005

根据rotor中对于syncblk.h的定义,
[cpp] view plaincopy
DWORD GetHeaderSyncBlockIndex() 
    { 
        LEAF_CONTRACT; 
 
        // pull the value out before checking it to avoid race condition 
        DWORD value = m_SyncBlockValue; 
        if ((value & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE)) != BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX) 
            return 0; 
        return value & MASK_SYNCBLOCKINDEX; 
    } 
#define BIT_SBLK_IS_HASHCODE            0x04000000
#define BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX    0x08000000

如果08000005只设置了掩码0x8000000,那么5就是syncblk的index,如果同时也设置了HASHCODE掩码(0x04000000),那后面的数字就是hashcode。因此这里我们可以确定5为syncblk的index。
接下来查看syncblk, 可以看到这个锁的拥有者是3号线程
0:004> !syncblk 5
Index         SyncBlock MonitorHeld Recursion Owning Thread Info          SyncBlock Owner
    5 00000000012e9f48            3         1 00000000012e6f40   7f0  3   0000000003023c08 System.Object
-----------------------------
Total           5
CCW             0
RCW             0
ComClassFactory 0
Free            0

AutoResetEvent/ManualResetEvent
AutoResetEvent/MannualResetEvent造成的等待线程栈如下,这里是调用的AutoResetEvent.WaitOne方法,
0:003> !clrstack
OS Thread Id: 0x21a0 (3)
Child-SP         RetAddr          Call Site
000000001b0defe0 000007ff98500623 System.Threading.WaitHandle.WaitOne(Int64, Boolean)
000000001b0df020 000007fff2222bdb Synchronization.TestAutoResetEvent.ThreadProc()
000000001b0df0a0 000007fff22ba9bd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001b0df0f0 000007fff7dbd552 System.Threading.ThreadHelper.ThreadStart()

相应的AutoResetEvent object肯定在调用栈上,通过以下命令查看,
0:003> !dso
OS Thread Id: 0x21a0 (3)
RSP/REG          Object           Name
rcx              0000000002603c20 Microsoft.Win32.SafeHandles.SafeWaitHandle
000000001b0de868 0000000002604018 Microsoft.Win32.SafeHandles.SafeFileHandle
000000001b0ded18 0000000002607a00 System.Threading.ThreadHelper
000000001b0dedf0 0000000002603c70 Microsoft.Win32.SafeHandles.SafeWaitHandle
000000001b0deef0 0000000002605e90 System.IO.StreamWriter
000000001b0def18 0000000002607a00 System.Threading.ThreadHelper
000000001b0def40 000000000260a608 System.Char[]    (System.Char[])
000000001b0def48 000000000260a608 System.Char[]    (System.Char[])
000000001b0def50 0000000002605e90 System.IO.StreamWriter
000000001b0def60 000000000260a4f8 System.Object[]    (System.Object[])
000000001b0def98 0000000002608050 System.String
000000001b0defc0 0000000002609fe8 System.Threading.ContextCallback
000000001b0defd0 0000000002608080 System.Threading.ExecutionContext
000000001b0df000 0000000002609fe8 System.Threading.ContextCallback
000000001b0df008 0000000002609fe8 System.Threading.ContextCallback
000000001b0df010 0000000002608080 System.Threading.ExecutionContext
000000001b0df020 0000000002606fd0 System.IO.TextWriter+SyncTextWriter
000000001b0df040 0000000002608050 System.String
000000001b0df048 0000000002607998 System.Threading.Thread
000000001b0df050 0000000002608050 System.String
000000001b0df058 0000000002603bf0 System.Threading.AutoResetEvent
000000001b0df060 0000000002603bf0 System.Threading.AutoResetEvent
000000001b0df070 0000000002603c40 System.Threading.AutoResetEvent
000000001b0df078 0000000002603c40 System.Threading.AutoResetEvent
000000001b0df0a0 0000000002607958 System.Threading.ThreadStart
000000001b0df0c8 0000000002608080 System.Threading.ExecutionContext
000000001b0df0e0 0000000002607a00 System.Threading.ThreadHelper
000000001b0df100 0000000002607a00 System.Threading.ThreadHelper
000000001b0df140 0000000002607a28 System.Threading.ThreadStart
000000001b0df2c8 0000000002607a28 System.Threading.ThreadStart
000000001b0df4c0 0000000002607a28 System.Threading.ThreadStart
000000001b0df4d8 0000000002607a28 System.Threading.ThreadStart

查看具体的AutoResetEvent object对象信息,找到对应的系统handle值,
0:003> !do 0000000002603bf0
Name: System.Threading.AutoResetEvent
MethodTable: 000007fff2355908
EEClass: 000007fff1f67968
Size: 48(0x30) bytes
 (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fff2367510  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fff236a628  400060f       18        System.IntPtr  1 instance              1b4 waitHandle
000007fff2355e40  4000610       10 ...es.SafeWaitHandle  0 instance 0000000002603c20 safeWaitHandle
000007fff2366df0  4000611       20       System.Boolean  1 instance                0 hasThreadAffinity
000007fff236a628  4000612      9f8        System.IntPtr  1   shared           static InvalidHandle

0:003> !handle 1b4 ff
Handle 1b4
  Type             Event
  Attributes       0
  GrantedAccess    0x1f0003:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState,ModifyState
  HandleCount      2
  PointerCount     524288
  Name             <none>
  Object Specific Information
    Event Type Auto Reset
    Event is Waiting

线程的WaitOne方法在等待其他线程调用AutoResetEvent.Set方法来解开,接下来要查看是否存在其他线程会最终调用Set方法来解开该线程的等待状态。
查看源代码,找到AutoResetEvent对象声明的可见范围
在可见范围内找到所有对于Set方法的调用路径,查看当前所有运行线程是否有线程运行在该路径上, 查看所有托管线程栈命令~*e!clrstack
如果没有,查看是否是由于某些条件判断而跨过了该路径,或者在调用set方法之前发生了异常,查看所有发生的异常命令: !dae

Mutex
Mutext等待的调用栈如下,
OS Thread Id: 0x1bfc (5)
Child-SP         RetAddr          Call Site
000000001b07eda0 000007ff9850043f System.Threading.WaitHandle.WaitOne(Int64, Boolean)
000000001b07ede0 000007ff98500397 Synchronization.TestMutex.UseResource()
000000001b07ee60 000007fff2222bdb Synchronization.TestMutex.MyThreadProc()
000000001b07eea0 000007fff22ba9bd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001b07eef0 000007fff7dbd552 System.Threading.ThreadHelper.ThreadStart()

找到调用栈上的Mutex object,
0:005> !dso
OS Thread Id: 0x1bfc (5)
RSP/REG          Object           Name
000000001b07ead8 00000000024b5c78 System.Threading.ThreadHelper
000000001b07ebb0 00000000024b3d28 Microsoft.Win32.SafeHandles.SafeWaitHandle
000000001b07ecd8 00000000024b5c78 System.Threading.ThreadHelper
000000001b07ed80 00000000024b5fe8 System.Threading.ContextCallback
000000001b07ed90 00000000024b5e00 System.Threading.ExecutionContext
000000001b07edc0 00000000024b5fe8 System.Threading.ContextCallback
000000001b07edc8 00000000024b5fe8 System.Threading.ContextCallback
000000001b07edd0 00000000024b5e00 System.Threading.ExecutionContext
000000001b07ee00 00000000024b3bf0 System.Threading.Mutex
000000001b07ee08 00000000024b3bf0 System.Threading.Mutex
000000001b07ee50 00000000024b5fe8 System.Threading.ContextCallback
000000001b07ee90 00000000024b5e00 System.Threading.ExecutionContext
000000001b07eec8 00000000024b5e00 System.Threading.ExecutionContext
000000001b07eee0 00000000024b5c78 System.Threading.ThreadHelper
000000001b07ef00 00000000024b5c78 System.Threading.ThreadHelper
000000001b07ef40 00000000024b5ca0 System.Threading.ThreadStart
000000001b07f0c8 00000000024b5ca0 System.Threading.ThreadStart
000000001b07f2c0 00000000024b5ca0 System.Threading.ThreadStart
000000001b07f2d8 00000000024b5ca0 System.Threading.ThreadStart

查看Mutex对象具体信息并找到对应内核对象的handle,查看handle信息

0:005> !do 00000000024b3bf0
Name: System.Threading.Mutex
MethodTable: 000007fff23740a0
EEClass: 000007fff2012f80
Size: 48(0x30) bytes
 (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fff2367510  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fff236a628  400060f       18        System.IntPtr  1 instance              1b0 waitHandle
000007fff2355e40  4000610       10 ...es.SafeWaitHandle  0 instance 00000000024b3d28 safeWaitHandle
000007fff2366df0  4000611       20       System.Boolean  1 instance                1 hasThreadAffinity
000007fff236a628  4000612      9f8        System.IntPtr  1   shared           static InvalidHandle
                                 >> Domain:Value  00000000004baba0:ffffffffffffffff <<
000007fff2366df0  4000659      a08       System.Boolean  1   shared           static dummyBool
                                 >> Domain:Value  00000000004baba0:NotInit  <<
0:005> !handle 1b0 ff
Handle 1b0
  Type             Mutant
  Attributes       0
  GrantedAccess    0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
  HandleCount      2
  PointerCount     524286
  Name             <none>
  Object Specific Information
    Mutex is Owned
    Mutant Owner 180.1628

找到mutex相应的拥有者线程 - 0x1628,为4号线程,
0:005> !threads
ThreadCount: 5
UnstartedThread: 0
BackgroundThread: 2
PendingThread: 0
DeadThread: 1
Hosted Runtime: no
                                              PreEmptive                                                Lock
       ID OSID        ThreadOBJ     State   GC     GC Alloc Context                  Domain           Count APT Exception
   0    1  2cc 00000000005152d0   201a220 Enabled  00000000024b5e90:00000000024b5fd0 00000000004baba0     0 MTA
   2    2 27fc 000000001ab80080      b220 Enabled  0000000000000000:0000000000000000 00000000004baba0     0 MTA (Finalizer)
XXXX    3    0 000000001aba3590      9820 Enabled  0000000000000000:0000000000000000 00000000004baba0     0 Ukn
   4    4 1628 000000001ab9a350   200b020 Enabled  00000000024ba170:00000000024bbfd0 00000000004baba0     0 MTA
   5    5 1bfc 000000001ab9d180   200b020 Enabled  0000000000000000:0000000000000000 00000000004baba0     0 MTA

查看4号线程的调用栈发现4号线程正在Sleep。
0:004> kL
Child-SP          RetAddr           Call Site
00000000`1af7e888 000007f8`0e6b11f2 ntdll!NtDelayExecution+0xa
00000000`1af7e890 000007ff`f803369d KERNELBASE!SleepEx+0xaa
00000000`1af7e930 000007ff`f7c2e7fd mscorwks!EESleepEx+0x2d
00000000`1af7e9b0 000007ff`f81f0769 mscorwks!Thread::UserSleep+0x71
00000000`1af7ea10 000007ff`98500491 mscorwks!ThreadNative::Sleep+0xf9
00000000`1af7ebc0 000007ff`98500397 Synchronization!Synchronization.TestMutex.UseResource()+0xa1
00000000`1af7ec40 000007ff`f2222bdb Synchronization!Synchronization.TestMutex.MyThreadProc()+0x37
00000000`1af7ec80 000007ff`f22ba9bd mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x9b
00000000`1af7ecd0 000007ff`f7dbd552 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+0x4d
00000000`1af7ed20 000007ff`f7cfa283 mscorwks!CallDescrWorker+0x82
00000000`1af7ed70 000007ff`f819c7af mscorwks!CallDescrWorkerWithHandler+0xd3
00000000`1af7ee10 000007ff`f7be4415 mscorwks!MethodDesc::CallDescr+0x2af
00000000`1af7f050 000007ff`f7d3cda4 mscorwks!ThreadNative::KickOffThread_Worker+0x191
00000000`1af7f370 000007ff`f7d23721 mscorwks!ManagedThreadBase_DispatchInner+0x2c
00000000`1af7f3c0 000007ff`f7c1fc59 mscorwks!ManagedThreadBase_DispatchMiddle+0x9d
00000000`1af7f490 000007ff`f7d7c949 mscorwks!ManagedThreadBase_DispatchOuter+0x31
00000000`1af7f4d0 000007ff`f7d472d3 mscorwks!ManagedThreadBase_FullTransitionWithAD+0x35
00000000`1af7f530 000007ff`f7d3f3a4 mscorwks!ThreadNative::KickOffThread+0xd3
00000000`1af7f610 000007f8`0f16167e mscorwks!Thread::intermediateThreadProc+0x78
00000000`1af7f7e0 000007f8`116d3501 KERNEL32!BaseThreadInitThunk+0x1a
00000000`1af7f810 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Semaphore
调试Semaphore的等待与前面AutoResetEvent思路一致,
0:003> !clrstack
OS Thread Id: 0xc68 (3)
Child-SP         RetAddr          Call Site
000000001b54eee0 000007ff985003c3 System.Threading.WaitHandle.WaitOne(Int64, Boolean)
000000001b54ef20 000007fff2222bdb Synchronization.TestSemaphore.Worker(System.Object)
000000001b54ef90 000007fff28c80dd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001b54efe0 000007fff7dbd552 System.Threading.ThreadHelper.ThreadStart(System.Object)
0:003> !dso
OS Thread Id: 0xc68 (3)
RSP/REG          Object           Name
r10              0000000002a7ffe8 System.Object[]
000000001b54e768 0000000002a76210 Microsoft.Win32.SafeHandles.SafeFileHandle
000000001b54ec18 0000000002a73d80 System.Threading.ThreadHelper
000000001b54ecf0 0000000002a73cb8 Microsoft.Win32.SafeHandles.SafeWaitHandle
000000001b54edf0 0000000002a78088 System.IO.StreamWriter
000000001b54ee18 0000000002a73d80 System.Threading.ThreadHelper
000000001b54ee40 0000000002a80158 System.Char[]    (System.Char[])
000000001b54ee48 0000000002a80158 System.Char[]    (System.Char[])
000000001b54ee50 0000000002a78088 System.IO.StreamWriter
000000001b54ee60 0000000002a7ffe8 System.Object[]    (System.Object[])
000000001b54ee98 0000000002a73de8 System.Int32
000000001b54eec0 0000000002a75fe8 System.Threading.ContextCallback
000000001b54eed0 0000000002a73e00 System.Threading.ExecutionContext
000000001b54ef00 0000000002a75fe8 System.Threading.ContextCallback
000000001b54ef08 0000000002a75fe8 System.Threading.ContextCallback
000000001b54ef10 0000000002a73e00 System.Threading.ExecutionContext
000000001b54ef20 0000000002a791c8 System.IO.TextWriter+SyncTextWriter
000000001b54ef48 0000000002a73c88 System.Threading.Semaphore
000000001b54ef50 0000000002a73c88 System.Threading.Semaphore
000000001b54ef80 0000000002a73e00 System.Threading.ExecutionContext
000000001b54ef90 0000000002a73de8 System.Int32
000000001b54efb8 0000000002a73de8 System.Int32
000000001b54efc0 0000000002a73e00 System.Threading.ExecutionContext
000000001b54efd0 0000000002a73d80 System.Threading.ThreadHelper
000000001b54eff0 0000000002a73d80 System.Threading.ThreadHelper
000000001b54eff8 0000000002a73de8 System.Int32
000000001b54f030 0000000002a73da8 System.Threading.ParameterizedThreadStart
000000001b54f038 0000000002a73de8 System.Int32
000000001b54f1b8 0000000002a73da8 System.Threading.ParameterizedThreadStart
000000001b54f1c0 0000000002a73de8 System.Int32
000000001b54f3b8 0000000002a73de8 System.Int32
000000001b54f3c0 0000000002a73da8 System.Threading.ParameterizedThreadStart
000000001b54f3e0 0000000002a73da8 System.Threading.ParameterizedThreadStart
000000001b54f3e8 0000000002a73de8 System.Int32
0:003> !do 0000000002a73c88
Name: System.Threading.Semaphore
MethodTable: 000007fff17e8c68
EEClass: 000007fff15635f0
Size: 48(0x30) bytes
 (C:\windows\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fff2367510  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fff236a628  400060f       18        System.IntPtr  1 instance              1c8 waitHandle
000007fff2355e40  4000610       10 ...es.SafeWaitHandle  0 instance 0000000002a73cb8 safeWaitHandle
000007fff2366df0  4000611       20       System.Boolean  1 instance                0 hasThreadAffinity
000007fff236a628  4000612      9f8        System.IntPtr  1   shared           static InvalidHandle
                                 >> Domain:Value  0000000000b6aba0:ffffffffffffffff <<
000007fff236ee90  4001083      920         System.Int32  1   static              260 MAX_PATH
0:003> !handle 1c8 ff
Handle 1c8
  Type             Semaphore
  Attributes       0
  GrantedAccess    0x1f0003:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState,ModifyState
  HandleCount      2
  PointerCount     524289
  Name             <none>
  Object Specific Information
    Semaphore Count 0
    Semaphore Limit 3