《Advanced .NET Debugging》 读书笔记 Listing 6-6: Orphaned locks的简单示例
时间:2011-01-09 来源:李志鹏
using System;
using System.Text;
using System.Threading;
namespace Advanced.NET.Debugging.Chapter6
{
internal class DBWrapper1
{
private string connectionString;
public DBWrapper1(string conStr)
{
this.connectionString = conStr;
}
}
class Exc
{
private static DBWrapper1 db1;
static void Main(string[] args)
{
db1 = new DBWrapper1("DB1");
Thread newThread = new Thread(ThreadProc);
newThread.Start();
Thread.Sleep(500);
Console.WriteLine("Acquiring lock");
Monitor.Enter(db1);
//
// Do some work
//
Console.WriteLine("Releasing lock");
Monitor.Exit(db1);
}
private static void ThreadProc()
{
try
{
Monitor.Enter(db1);
Call3rdPartyCode(null);
Monitor.Exit(db1);
}
catch (Exception)
{
Console.WriteLine("3rd party code threw an exception");
}
}
private static void Call3rdPartyCode(Object obj)
{
if (obj == null)
{
throw new NullReferenceException();
}
//
// Do some work
//
}
}
}
程序的问题在于,在ThreadProc里面使用Monitor.Enter锁定db1以后,执行的方法Call3rdPartyCode将会抛出异常。抛出该异常的结果是,db1得不到释放,从而使得该线程出现一个orphaned lock。
1. 双击06exception.exe 运行,程序将进入dead lock状态。
2. 执行 .loadby sos.dll mscorwks
3.执行 .load sosex.dll
4. 执行 !dlk 结果如下:
可见程序进入死锁的原因是0x1这个线程在等待一个orphaned SyncBlock,而该lock被orphan的原因是拥有它的thread0x3在抛出异常以后,已经结束了。
5. 也可以使用别的方法来查看。切换到~0s, 执行 !dumpstackobjects:
可以找到此时有问题的对象的地址。
6. 执行 dd 0x0000000002673930-0x4 结果如下:
从08可以判定是syncblk,其编号为02。
7. 执行 !clrblk 0x2 查看0x2这个syncblk的情况。 执行 !threads 可以查看thread的情况。可以看出,该syncblk是线程xxx拥有的,而线程xxxx正好有一个lock。