Monitor

 

将为每个同步对象来维护以下信息:
对当前持有锁的线程的引用。
对就绪队列的引用,它包含准备获取锁的线程。
对等待队列的引用,它包含正在等待锁定对象状态变化通知的线程。

Monitor有几个主要的方法,我们需要了解


1.Monitor.Enter和Monitor.Exit
他们两个是一起的,我们在一个方法中,如果调用了Monitor.Enter,那么就必须有相应的Monitory.Exit方法与之对应。这两个方法用于锁定对象和取消锁定对象,在平时的使用中,我们一般用lock取代他们。


2.Monitor.Wait方法
当线程调用 Wait 时,它释放对象的锁并进入对象的等待队列,对象的就绪队列中的下一个线程(如果有)获取锁并拥有对对象的独占使用。

3.Monitor.Pulse方法
当前线程调用此方法以便向队列中的下一个线程发出锁的信号。接收到脉冲后,等待线程就被移动到就绪队列中。在调用 Pulse 的线程释放锁后,就绪队列中的下一个线程(不一定是接收到脉冲的线程)将获得该锁。

 

using System; using System.Collections.Generic; using System.Threading; namespace ConsoleApplication6 { public class Cell { int cellContents; // Cell对象里边的内容 bool readerFlag = false; // 状态标志,为true时可以读取,为false则正在写入 public int ReadFromCell() { lock (this) // Lock关键字保证了什么,请大家看前面对lock的介绍 { if (!readerFlag)//如果现在不可读取 { try { //等待WriteToCell方法中调用Monitor.Pulse()方法 Monitor.Wait(this); } catch (SynchronizationLockException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } } Console.WriteLine("Consume: {0}", cellContents); readerFlag = false; //重置readerFlag标志,表示消费行为已经完成 Monitor.Pulse(this); //通知WriteToCell()方法(该方法在另外一个线程中执行,等待中) } return cellContents; } public void WriteToCell(int n) { lock (this) { if (readerFlag) { try { Monitor.Wait(this); } catch (SynchronizationLockException e) { //当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用 Console.WriteLine(e); } catch (ThreadInterruptedException e) { //当线程在等待状态的时候中止 Console.WriteLine(e); } } cellContents = n; Console.WriteLine("Produce: {0}", cellContents); readerFlag = true; Monitor.Pulse(this); //通知另外一个线程中正在等待的ReadFromCell()方法 } } } public class CellProd { Cell cell; // 被操作的Cell对象 int quantity = 1; // 生产者生产次数,初始化为1 public CellProd(Cell box, int request) { //构造函数 cell = box; quantity = request; } public void ThreadRun() { for (int looper = 1; looper <= quantity; looper++) cell.WriteToCell(looper); //生产者向操作对象写入信息 } } public class CellCons { Cell cell; int quantity = 1; public CellCons(Cell box, int request) { cell = box; quantity = request; } public void ThreadRun() { int valReturned; for (int looper = 1; looper <= quantity; looper++) valReturned = cell.ReadFromCell();//消费者从操作对象中读取信息 } } public class MonitorSample { public static void Main(String[] args) { int result = 0; //一个标志位,如果是0表示程序没有出错,如果是1表明有错误发生 Cell cell = new Cell(); //下面使用cell初始化CellProd和CellCons两个类,生产和消费次数均为20次 CellProd prod = new CellProd(cell, 5); CellCons cons = new CellCons(cell, 5); Thread producer = new Thread(new ThreadStart(prod.ThreadRun)); Thread consumer = new Thread(new ThreadStart(cons.ThreadRun)); //生产者线程和消费者线程都已经被创建,但是没有开始执行 try { producer.Start(); consumer.Start(); producer.Join(); consumer.Join(); Console.ReadLine(); } catch (ThreadStateException e) { //当线程因为所处状态的原因而不能执行被请求的操作 Console.WriteLine(e); result = 1; } catch (ThreadInterruptedException e) { //当线程在等待状态的时候中止 Console.WriteLine(e); result = 1; } //尽管Main()函数没有返回值,但下面这条语句可以向父进程返回执行结果 Environment.ExitCode = result; } } }

Monitor 类似实现了一个线程池,而信号量:MenualRestEvent不具备队列的概念




你可能感兴趣的:(Monitor)