利用using语句解决Lock抛出异常时发生死锁的问题

大家有兴趣可以加我QQ群交流:14792063 广州软件开发团队

先来看一段我们多线程编程时常用的lock关键字程序片段

lock(obj)
{
// Do sth1
// Do sth2
}

 

知道lock工作原理的人都知道,他的实质其实等于

Monitor.Enter(obj); //acquire lock on object
// Do sth1
// Do sth2
Monitor.Exit(obj); //release lock

 

 

 

不过这样会有一个潜在的问题:

 

如果在Do sth1Do sth2中某处抛出了exception,那就会有大问题了,

Monitor.Exit(obj);这一语句不会执行,obj将继续保持lock状态永远得不到解锁。 

 

解决这个和异常有关的问题,很自然可以想到finally语句:

Monitor.Enter(obj);
try
{
// Do sth1
// Do sth2
}
catch 
{

}
finally
{
Monitor.Exit(obj);
}
  

 

 

 

问题解决了,不过try/catch/finally代码段写起来很麻烦,看起来也不爽,想到C#里有个和finally作用差不多的关键字using,它在中间语句发生异常时也能析构对象,而且使用起来简约、整洁

using(obj)
{

}

 

 

 

 

不过using使用有一个前提,那就是这里的obj必须要继承IDispose接口,接下来就要引出本文的终极解决方案了,那就是设计一个类来实现这些工作,设置一个obj来接收要锁定的对象,这个类在初始化时Monitor.Enter(obj);在实现IDispose接口的Dispose()Monitor.Exit(obj);然后在using语句中使用这个类的对象

 

 

下面看看ThreadLock这个类

代码
using System;
namespace MyThread
{
    
public class ThreadLock : IDisposable
    {
        
private object objLock;

        
public ThreadLock() 
        {
        }
        
        
//这里弄一个静态方法,为了使用方便
        public static ThreadLock Lock(object objLock)
        {
            
return new ThreadLock(objLock); 软件开发网 
        }

        
public ThreadLock(object objLock)
        {
            
this.objLock = objLock;
            Monitor.Enter(objLock);
        }

        
public void Dispose() 

        {
            Monitor.Exit(objLock);
        }
    }
}

 

 

 

有了上面这个类,使用起来就很简单了

 

 

using (ThreadLock.Lock(obj))
{
    
// Do sth1
    
// Do sth2
}

 


posted on 2010-07-19 07:06  welcomesay  阅读(1666)  评论(2编辑  收藏  举报

导航