蛙蛙推荐:新学一招,教大家怎么看死锁

新学一招,教大家怎么看死锁

 

代码如下,3个线程,第一个线程得到锁,Sleep一分钟,后两个线程都等待锁。

 

class Program

{

    static List<int> _list = new List<int>();

    static object _syncRoot = new object();

    static void Main(string[] args)

    {

        Thread t = new Thread(F1);

        t.Start();

 

        Thread.Sleep(1000);

        t = new Thread(F2);

        t.Start();

 

        t = new Thread(F3);

        t.Start();

        Console.ReadKey();

    }

 

    static void F1(object o)

    {

        Console.WriteLine("enter F1");

        lock (_syncRoot)

        {

            Console.WriteLine("F1 enter lock");

            _list.Add(1);

            Thread.Sleep(1000*60);

        }

        Console.WriteLine("F1 leave lock");

    }

    static void F2(object o)

    {

        Console.WriteLine("enter F2");

        lock (_syncRoot)

        {

            Console.WriteLine("F2 enter lock");

            _list.Add(2);

        }

        Console.WriteLine("F2 leave lock");

    }

    static void F3(object o)

    {

        Console.WriteLine("enter F3");

        lock (_syncRoot)

        {

            Console.WriteLine("F3 enter lock");

            _list.Add(3);

        }

        Console.WriteLine("F3 leave lock");

    }

}

 

用windbg按f6附加进程,看同步块信息

0:013> !syncblk

Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner

   18 001b623c            5         1 001eae28  164c  12   0143d54c System.Object

-----------------------------

Total           18

CCW             2

RCW             0

ComClassFactory 0

Free            0

 

12号线程获取了0143d54c资源的锁,有2(MonitorHeld的值减去1,除以2)个线程在等待这个锁。

在.net 1.1里可以直接列出哪些线程在等待这个锁,.net 2.0就不好判断了,这时候可以输入“~* kv”命令,然后搜索“JIT_MonEnterWorker_Portable”和“JITutil_MonContention”,然后看那行的Args列的第一段儿,也就是该方法的第一个参数,如果是!syncblk打出的SyncBlock列的值,那就说明该线程正在等待这个锁,如下

 

13  Id: 1840.8f4 Suspend: 1 Teb: 7ff3e000 Unfrozen

ChildEBP RetAddr  Args to Child             

WARNING: Stack unwind information not available. Following frames may be wrong.

0461f1dc 79f4c88a 00000001 001b6250 00000000 ntdll!KiFastSystemCallRet

0461f244 79f4c4bb 00000001 001b6250 00000000 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0x6f (FPO: [Non-Fpo])

0461f264 79f4c5c4 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateAptStateWait+0x3c (FPO: [Non-Fpo])

0461f2e8 79f4c659 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateWaitWorker+0x13c (FPO: [Non-Fpo])

0461f338 79f4c7d9 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateWait+0x40 (FPO: [Non-Fpo])

0461f394 79e8c54e ffffffff 00000001 00000000 mscorwks!CLREvent::WaitEx+0xf7 (FPO: [Non-Fpo])

0461f3a8 79f649fa ffffffff 00000001 00000000 mscorwks!CLREvent::Wait+0x17 (FPO: [Non-Fpo])

0461f434 79fb874c 001eb4d0 ffffffff 001eb4d0 mscorwks!AwareLock::EnterEpilog+0x8c (FPO: [Non-Fpo])

0461f450 79fb86d0 e937bce2 0461f52c 00000000 mscorwks!AwareLock::Enter+0x61 (FPO: [Non-Fpo])

0461f4f0 00da1481 0143d54c 00000000 00000000 mscorwks!JIT_MonEnterWorker_Portable+0xb3 (FPO: [Non-Fpo])

0461f538 79a00eee 00000000 00000000 00000000 lockTest!lockTest.Program.F2(System.Object)+0x51 (Managed) [D:"huhao_Document"Visual Studio 2005"Projects"ConsoleApplication1"lockTest"Program.cs @ 40]

0461f544 792e019f 00000000 00000000 00000000 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(System.Object)+0x72a25e (Managed)

0461f558 797db48a 00000000 00000000 00000000 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x6f (Managed)

0461f570 79e71b4c 00000000 00000000 00000000 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart(System.Object)+0x4a (Managed)

0461f580 79e821b1 0461f650 00000000 0461f620 mscorwks!CallDescrWorker+0x33

0461f600 79e96501 0461f650 00000000 0461f620 mscorwks!CallDescrWorkerWithHandler+0xa3 (FPO: [Non-Fpo])

0461f738 79e96534 79253444 0461f894 0461f7c4 mscorwks!MethodDesc::CallDescr+0x19c (FPO: [Non-Fpo])

0461f754 79e96552 79253444 0461f894 0461f7c4 mscorwks!MethodDesc::CallTargetWorker+0x1f (FPO: [Non-Fpo])

0461f76c 79f3d803 0461f7c4 e937b146 001eb4d0 mscorwks!MethodDescCallSite::CallWithValueTypes+0x1a (FPO: [Non-Fpo])

0461f954 79e9845f 0461fad0 00000000 00000000 mscorwks!ThreadNative::KickOffThread_Worker+0x192 (FPO: [Non-Fpo])

 

  14  Id: 1840.14e0 Suspend: 1 Teb: 7ff3d000 Unfrozen

ChildEBP RetAddr  Args to Child             

WARNING: Stack unwind information not available. Following frames may be wrong.

0471f0f4 79f4c88a 00000001 001b6250 00000000 ntdll!KiFastSystemCallRet

0471f15c 79f4c4bb 00000001 001b6250 00000000 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0x6f (FPO: [Non-Fpo])

0471f17c 79f4c5c4 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateAptStateWait+0x3c (FPO: [Non-Fpo])

0471f200 79f4c659 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateWaitWorker+0x13c (FPO: [Non-Fpo])

0471f250 79f4c7d9 00000001 001b6250 00000000 mscorwks!Thread::DoAppropriateWait+0x40 (FPO: [Non-Fpo])

0471f2ac 79e8c54e ffffffff 00000001 00000000 mscorwks!CLREvent::WaitEx+0xf7 (FPO: [Non-Fpo])

0471f2c0 79f649fa ffffffff 00000001 00000000 mscorwks!CLREvent::Wait+0x17 (FPO: [Non-Fpo])

0471f34c 79fb874c 002040b8 ffffffff 001b623c mscorwks!AwareLock::EnterEpilog+0x8c (FPO: [Non-Fpo])

0471f368 79f64f88 e927bbc2 002040b8 002040b8 mscorwks!AwareLock::Enter+0x61 (FPO: [Non-Fpo])

0471f3d0 79f64d67 ffffffff e927bc62 0471f4ac mscorwks!AwareLock::Contention+0x199 (FPO: [Non-Fpo])

0471f470 00da1549 0143d54c 00000000 00000000 mscorwks!JITutil_MonContention+0xa3 (FPO: [Non-Fpo])

0471f4b8 79a00eee 00000000 00000000 00000000 lockTest!lockTest.Program.F3(System.Object)+0x51 (Managed) [D:"huhao_Document"Visual Studio 2005"Projects"ConsoleApplication1"lockTest"Program.cs @ 50]

0471f4c4 792e019f 00000000 00000000 00000000 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(System.Object)+0x72a25e (Managed)

0471f4d8 797db48a 00000000 00000000 00000000 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x6f (Managed)

0471f4f0 79e71b4c 00000000 00000000 00000000 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart(System.Object)+0x4a (Managed)

0471f500 79e821b1 0471f5d0 00000000 0471f5a0 mscorwks!CallDescrWorker+0x33

0471f580 79e96501 0471f5d0 00000000 0471f5a0 mscorwks!CallDescrWorkerWithHandler+0xa3 (FPO: [Non-Fpo])

0471f6b8 79e96534 79253444 0471f814 0471f744 mscorwks!MethodDesc::CallDescr+0x19c (FPO: [Non-Fpo])

0471f6d4 79e96552 79253444 0471f814 0471f744 mscorwks!MethodDesc::CallTargetWorker+0x1f (FPO: [Non-Fpo])

0471f6ec 79f3d803 0471f744 e927b0c6 002040b8 mscorwks!MethodDescCallSite::CallWithValueTypes+0x1a (FPO: [Non-Fpo])

 

以上片段说明13号和14号线程,正在等待12号线程所拥有的锁,在排查死锁问题的时候,如果syncblk打出多行,用上面的方法就可以看到是否有互相等待的资源,然后再想法解决掉。以前用“~*e!dso”也能打出所有线程等待的syncblk object对象,但那样来确定是否是这个线程等待这个锁有些没有根据,只说明这个线程的调用栈上引用了这个同步块儿对象。

参考:http://support.microsoft.com/kb/812614

!SyncBlk in SOS for .NET Framework 2.0
http://dotnetdebug.net/2006/02/23/syncblk-in-sos-for-net-framework-20/comment-page-1/#comment-30066

.NET调试实例-实验1:死锁 - 回顾 (原创翻译)
http://www.cnblogs.com/justinw/archive/2008/07/14/1242970.html

A Hang Scenario, Locks and Critical Sections
http://blogs.msdn.com/tess/archive/2006/01/09/a-hang-scenario-locks-and-critical-sections.aspx

备注:有时候等待所的时候非托管线程并不停在这两个调用栈上,用!u也看不出来和monitor相关的操作,这种情况我还没掌握如何分析,但~*e!dso,然后搜索!syncblk出来的lock object一般可以确定哪些线程等待哪个锁,笨办法,不知道准不准,前提是你尽量用单独的object做来加锁,这些对象保证不做其他用处,这样!dso出来就比较准了。

posted @ 2009-02-04 13:14  蛙蛙王子  Views(1133)  Comments(1Edit  收藏  举报