今天在写code时发现了原来代码里有一个AutoResetEvent,于是就研究了一下它的用法,这里做一下笔记。
AutoResetEvent根据我的理解,是做线程互斥时所使用的信号量,在有独占资源时使用,它提供了一对方法,WaitOne()与Set(),用以阻塞线程进入等待状态与发出信号让阻塞的线程放行,WaitOne()就像一个闸门,程序执行到这里会被阻塞,直到Set()方法被别的线程调用,发出信号,闸门打开,阻塞的线程才会继续执行,否则会一直等待下去。
这里使用了一个别人的例子,稍加修改,假设我现在要买书,买书分为三个步骤,决定要买的书(挑书),付钱,取书3步,由于我只有一个人,所以一次只能做一步,相当于独占资源,每做完一步,通知下个步骤进行,否则就处于阻塞状态。
我用3个线程来模拟,主线程选书,然后两个子线程模拟付钱和取书。代码如下:
class Program { static AutoResetEvent buyEvent = new AutoResetEvent(false);//选书信号量 static AutoResetEvent payEvent = new AutoResetEvent(false);//付钱信号量 static AutoResetEvent getEvent = new AutoResetEvent(true);//取书信号量,注意为true,第一次直接放行 const int bookCount = 10;//一共买10本书 static int bookNum = 0;//当前第几本书 static void Main(string[] args) { Thread payThread = new Thread(PayThread);//付钱线程 Thread getThread = new Thread(GetThread);//取书线程 payThread.Start(); getThread.Start(); for (int i = 1; i <= bookCount; i++) //开始选书 { getEvent.WaitOne(); //等待取书完成 bookNum = i; Console.WriteLine("Buy {0} book", bookNum); //选书 buyEvent.Set(); //选书完成 } //wait for the last getEvent return getEvent.WaitOne(); //等待最后一次取书完成,不然子线程还没跑完就被下面两个语句杀掉了 payThread.Abort(); //付钱线程终止 getThread.Abort(); //取书线程终止 Console.Read(); } static void PayThread() { while (true) { buyEvent.WaitOne(); //等待选书完成 Console.WriteLine("Pay {0} book", bookNum); //付钱 payEvent.Set(); //付钱完成 } } static void GetThread() { while (true) { payEvent.WaitOne(); //等待付钱完成 Console.WriteLine("Get {0} book", bookNum); //取书 getEvent.Set(); //取书完成 } } }
代码里有两点需要注意的地方
1.在 getEvent 初始化时,我们把它设置为true,这是为了在第一次选书时能够顺利放行,因为第一次选书不需要等待取书完成。
2.在两个子进程结束之前,调用一次getEvent.WaitOne()这是确保最后一次取书能够执行完,不然子线程还没有处理完就被主线程杀掉了。
好了,这就是一个WaitOne和AutoResetEvent的简单应用,下面是一些参考链接:
http://blog.csdn.net/lanruoshui/article/details/5411270
http://msdn.microsoft.com/zh-cn/library/system.threading.autoresetevent.aspx