當在C#使用多線程時就免不了使用AutoResetEvent和ManualResetEvent類,可以理解這兩個類可以通過設置信號來讓線程停下來或讓線程重新啟動,其實與操作系統里的信號量很相似(汗,考完考試已經有點忘記了)。下面上代碼
class Program { const int count = 10; //賦值為false也就是沒有信號 static AutoResetEvent myResetEvent = new AutoResetEvent(false); static int number; static void Main(string[] args) { Thread thread = new Thread(funThread); thread.Name = "QQ"; thread.Start(); for (int i = 1; i < count; i++) { Console.WriteLine("first number: {0}",i); number = i; //這里是設置為有信號 myResetEvent.Set(); Thread.Sleep(2000); } thread.Abort(); } static void funThread() { while (true) { //執行到這個地方時,會等待set調用后改變了信號才接着執行 myResetEvent.WaitOne(); Console.WriteLine("end {0} number: {1}", Thread.CurrentThread.Name, number); } } }
輸出結果為
first number:1
end QQ number:1
first number:2
end QQ number:3
.....
簡單來說只有調用Set()方法后才能執行WaitOne()后面的代碼,AutoResetEvent和ManualResetEvent分別都有Set()改變為有信號 ,Reset()改變為無信號,WaitOne()將會阻塞當前調用的線程,直到有信號為止,即執行了Set()方法,WaitOne()方法還可以帶指定時間的參數。
理解了AutoResetEvent后再理解ManualResetEvent也就不難了,AutoResetEvent與ManualResetEvent的區別是,AutoResetEvent.WaitOne()會自動改變事件對象的狀態,即AutoResetEvent.WaitOne()每執行一次,事件的狀態就改變一次,也就是從有信號變為無信號。而ManualResetEvent則是調用Set()方法后其信號量不會自動改變,除非再設置Reset()方法。
在.Net多線程編程中,AutoResetEvent和ManualResetEvent這兩個類經常用到, 他們的用法很類似,但也有區別。Set方法將信號置為發送狀態,Reset方法將信號置為不發送狀態,WaitOne等待信號的發送。可以通過構造函數的參數值來決定其初始狀態,若為true則非阻塞狀態,為false為阻塞狀態。如果某個線程調用WaitOne方法,則當信號處於發送狀態時,該線程會得到信號, 繼續向下執行。其區別就在調用后,AutoResetEvent.WaitOne()每次只允許一個線程進入,當某個線程得到信號后,AutoResetEvent會自動又將信號置為不發送狀態,則其他調用WaitOne的線程只有繼續等待.也就是說,AutoResetEvent一次只喚醒一個線程;而ManualResetEvent則可以喚醒多個線程,因為當某個線程調用了ManualResetEvent.Set()方法后,其他調用WaitOne的線程獲得信號得以繼續執行,而ManualResetEvent不會自動將信號置為不發送。也就是說,除非手工調用了ManualResetEvent.Reset()方法,則ManualResetEvent將一直保持有信號狀態,ManualResetEvent也就可以同時喚醒多個線程繼續執行。
上述理論部分理解了,請看下面代碼,和上邊代碼輸出結果是一致的:
class Program { const int count = 10; //賦值為false也就是沒有信號 static ManualResetEvent myResetEvent = new ManualResetEvent(false); static int number; static void Main(string[] args) { Thread thread = new Thread(funThread); thread.Name = "QQ"; thread.Start(); for (int i = 1; i < count; i++) { Console.WriteLine("first number: {0}", i); number = i; //這里是設置為有信號 myResetEvent.Set(); Thread.Sleep(2000); } thread.Abort(); Console.ReadKey(); } static void funThread() { while (true) { //執行到這個地方時,會等待set調用后改變了信號才接着執行 myResetEvent.WaitOne(); Console.WriteLine("end {0} number: {1}", Thread.CurrentThread.Name, number); myResetEvent.Reset();//#此處取消信號 注意 } } }
看懂了這兩處代碼,相比就會了解二者的區別了!