C#——ManualResetEvent的理解和用法
ManualResetEvent是C#中一个比较常用的工具,可用于线程间通信,实现一种类似信号量的功能。
这里的信号量与Java中的信号量Semaphore不同。
Java中的信号量Semaphore,是控制有限资源的并发访问。
这里的ManualResetEvent,更像是一种线程挡板。
先了解一下ManualResetEvent的基本用法:
1、初始化:public ManualResetEvent(bool initialState);
ManualResetEvent的构造方法有个bool型参数,当为true时,则表示有信号,为false时,则表示无信号。
这个怎么理解呢?我们接着看ManualResetEvent3个基本方法中的WaitOne方法。
2、WaitOne方法:WaitOne方法有几种4种重载,我在这里只对它的功能进行分析。
WaitOne方法,顾名思义,它会具有一种等待的功能,也就是线程阻塞。
这里的阻塞功能是有条件的,当无信号时,它是阻塞的,有信号时,它将无任何阻塞,被执行时就直接跳过了。
所以,回顾到1,当初始化ManualResetEvent时,initialState为false,WaitOne将会有阻塞效果,否则,没有阻塞效果。
3、Set方法:将ManualResetEvent对象的信号状态设为有信号状态,
这个时候WaitOne如果正在阻塞中的话,将会立即终止阻塞,向下继续执行。
而且这个状态一直不变的话,每次执行到WaitOne都将无任何阻塞。
4、Reset方法:
将ManualResetEvent对象的信号状态设为无信号状态,当下次执行到WaitOne时,又将重新开始阻塞。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadTest { class Program { static void Main(string[] args) { new ProductAndCostTester(); } } /// <summary> /// 生产消费模型 /// </summary> public class ProductAndCostTester { /// <summary> /// 生产线1线程 /// </summary> private Thread _producterThread1; /// <summary> /// 生产线2线程 /// </summary> private Thread _producterThread2; /// <summary> /// 消费线线程 /// </summary> private Thread _costerThread; /// <summary> /// 产品列表 /// </summary> private List<int> _goodList; /// <summary> /// ManualResetEvent实例 /// </summary> private ManualResetEvent _mre; public ProductAndCostTester() { _goodList = new List<int>(); _mre = new ManualResetEvent(false);//false初始化状态为无信号,将使WaitOne阻塞 _producterThread1 = new Thread(Product1); _producterThread1.Name = "Productor1"; _producterThread1.Start(); _producterThread2 = new Thread(Product2); _producterThread2.Name = "Productor2"; _producterThread2.Start(); _costerThread = new Thread(Cost); _costerThread.Name = "Costor"; _costerThread.Start(); } /// <summary> /// 生产线1 /// </summary> void Product1() { while (true) { Console.WriteLine(Thread.CurrentThread.Name + ":" + DateTime.Now.ToString("HH:mm:ss")); for (int i = 0; i < 3; i++) { _goodList.Add(1); } _mre.Set();//表示有信号了,通知WaitOne不再阻塞 Thread.Sleep(8000); } } /// <summary> /// 生产线2 /// </summary> void Product2() { while (true) { Console.WriteLine(Thread.CurrentThread.Name + ":" + DateTime.Now.ToString("HH:mm:ss")); for (int i = 0; i < 6; i++) { _goodList.Add(1); } _mre.Set();//表示有信号了,通知WaitOne不再阻塞 Thread.Sleep(10000); } } /// <summary> /// 消费线 /// </summary> void Cost() { while (true) { if (_goodList.Count > 0) { Console.WriteLine("Cost " + _goodList.Count + " at " + DateTime.Now.ToString("HH:mm:ss")); _goodList.Clear(); _mre.Reset();//重置为无信号了,使WaitOne可以再次阻塞 } else { Console.WriteLine("No cost at " + DateTime.Now.ToString("HH:mm:ss")); _mre.WaitOne();//如果没有可消费的产品,即无信号,则会阻塞 } } } } }