C#中多线程同步的Monitor理解(转)

.NET提供了System.Threading.Monitor类允许同一进城中的线程实现同步,是一种更快速、更轻量级的锁机制。可以使用该类来保护对某些变量的访问,或对某些一次只能在一个线程中执行的代码设置访问权限。
使用实例(片段代码):

readonly object theLock=new object();
 int num=0;

...... Monitor.Enter(theLock);
try{ ++num; }finally{ Monitor.Exit(theLock); }

Monitor与lock 
对以上代码的解读:

    1. Monitor.Enter(theLock)获得theLock对象锁;Monitor.Exit(theLock)释放theLock对象锁;
    2. 我们将所有对num变量的访问以对象锁的形式房在临界区,在每次访问前,访问者必须获得theLock对象实例的锁。theLock字段类型是 Object类型,它的实际类型无关紧要,但必须是引用类型即对象的实例,而不是值类型。为了安全起见,建议标记成readonly,以免theLock 被复制而造成混乱。
    3. 上述代码不够简洁,使用try/finally,而且一旦漏掉Monitor.Exit将会发生可怕的混乱。就此问题C#设计者引用了lock关键字,lock关键字代替了Monitor.Enter和Monitor.Exit,上述代码可简写为
  1. readonly object theLock=new object();
     int num=0;
     
     #其他代码...
     
     lock(theLock){
         ++num;
     }

    通知与等待

    • Monitor管理着两个线程队列:就绪队列(ready队列)和等待队列(waiting队列)。
    • ready队列保存的是准备获取锁的线程,就是说,如果某个线程(几座线程A)执行了Monitor.Wait(),那么ready队列中的第一个线程就会获得锁,开始运行;同时线程A自动进入waiting队列中的队尾进行排队。
    • waiting队列保存的是正在等待锁对象状态变化通知的线程,就是说如果某个线程执行了Moniotr.Pulse(),那么waiting队列中的对头线程就进入ready队列中。
    • 简单地说即是当前线程执行Monitor.Wait(),当前线程进入waiting队列并取ready队列对头线程运行;执行Monitor.Pulse把waiting队列的对头线程调入ready队列。
      Monitor类锁定一个对象
      当多线程公用一个对象时,也会出现和公用代码类似的问题,这种问题就不应该使用c# lock关键字,这里需要用到Threading中的一个类 Minotor,称之为监视器,Minotor提供了使线程共享资源的方案。
      Minotor类可以锁定一个对象,一个线程只有得到这把锁才可以对该对象进行操作。对象锁机制保证了再可能引起混乱的情况下一个时刻只有一个线程可以访问这个对象。Minotor必须和一个具体的对象相关联,但是由于他本身是一个静态类,所以不能使用他来定义对象,而却它的方法都是静态的,不能使用对象来引用。
      如下:
             
      [csharp] view plaincopy
      ......    
         
      Queue oQueue=new Queue();    
         
      ......    
         
      Monitor.Enter(oQueue);    
         
      ......//现在oQueue对象只能被当前线程操纵了    
         
      Monitor.Exit(oQueue);//释放锁    
      
      如上,当一个线程调用Minotor.Enter()方法锁定一个对象时,这个对象就归它所有了,其他线程想要访问这个对象,只有等待它使用Minoter.Exit()方法释放锁。
      一般为了保证线程最终都能释放锁,将Minotor.Exit()方法卸载try-catch-finally结构中的finally代码块中。

      出处:http://www.oseye.net/user/kevin/blog/127

posted @ 2014-07-15 11:22  邹邹  Views(602)  Comments(0)    收藏  举报