初次體驗
ManualResetEvent和AutoResetEvent主要負責多線程編程中的線程同步;以下一段是引述網上和MSDN的解析:
在.Net多線程編程中,AutoResetEvent和ManualResetEvent這兩個類經常用到, 他們的用法很類似,但也有區別。Set方法將訊號置為發送狀態,Reset方法將訊號置為不發送狀態,WaitOne等待訊號的發送。可以通過建構函式的參數值來決定其初始狀態,若為true則非阻塞狀態,為false為阻塞狀態。如果某個線程調用WaitOne方法,則當訊號處於發送狀態時,該線程會得到訊號, 繼續向下執行。其區別就在調用後,AutoResetEvent.WaitOne()每次只允許一個線程進入,當某個線程得到訊號後,AutoResetEvent會自動又將訊號置為不發送狀態,則其他調用WaitOne的線程只有繼續等待.也就是說,AutoResetEvent一次只喚醒一個線程;而ManualResetEvent則可以喚醒多個線程,因為當某個線程調用了ManualResetEvent.Set()方法後,其他調用WaitOne的線程獲得訊號得以繼續執行,而ManualResetEvent不會自動將訊號置為不發送。也就是說,除非手工調用了ManualResetEvent.Reset()方法,則ManualResetEvent將一直保持有訊號狀態,ManualResetEvent也就可以同時喚醒多個線程繼續執行。
本質上AutoResetEvent.Set()方法相當於ManualResetEvent.Set()+ManualResetEvent.Reset();
因此AutoResetEvent一次只能喚醒一個線程,其他線程還是堵塞
生動樣本
用一個三國演義的典故來寫段範例程式碼:
話說曹操率領80W大軍準備圍剿劉備和孫權,面對敵眾我寡的情況,諸葛亮與周瑜想到了一個妙計,用裝滿火藥桶的大船去衝擊曹操連在一起的戰船,計劃都安排好了,可謂“萬事俱備 只欠東風”。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace Test{ class Program { //預設訊號為不發送狀態 private static ManualResetEvent mre = new ManualResetEvent(false); static void Main(string[] args) { EastWind wind = new EastWind(mre); //啟動東風的線程 Thread thd = new Thread(new ThreadStart(wind.WindComming)); thd.Start(); mre.WaitOne();//萬事俱備只欠東風,事情卡在這裡了,在東風來之前,諸葛亮沒有進攻 //東風到了,可以進攻了 Console.WriteLine("諸葛亮大吼:東風來了,可以進攻了,滿載燃料的大船接著東風沖向曹操的戰船"); Console.ReadLine(); } } /// <summary> /// 傳說中的東風 /// </summary> class EastWind { ManualResetEvent _mre; /// <summary> /// 建構函式 /// </summary> /// <param name="mre"></param> public EastWind(ManualResetEvent mre) { _mre = mre; } /// <summary> /// 風正在吹過來 /// </summary> public void WindComming() { Console.WriteLine("東風正在吹過來"); for (int i = 0; i <= 5; i++) { Thread.Sleep(500); Console.WriteLine("東風吹啊吹,越來越近了..."); } Console.WriteLine("東風終於到了"); //通知諸葛亮東風已到,可以進攻了,通知阻塞的線程可以繼續執行了 _mre.Set(); } }}
運行結果: