一、兩者區別
1.ManualResetEvent 調用一次Set()后將允許恢復所有被阻塞線程。需手動在調用WaitOne()之后調用Reset()重置信號量狀態為非終止,然后再次調用WaitOne()的時候才能繼續阻塞線程,反之則不阻塞
2.AutoResetEvent,調用一次Set()只能繼續被阻塞的一個線程,多次調用Set()才行,但不需手動調用Reset();再次調用WaitOne()的時候又能阻塞線程,也是和前者的區別
3.兩者單個實例均可阻塞一個或多個線程,在多個線程中調用 主線程 創建的 兩者單個實例.WaitOne(),前提是兩者實例必須是非終止狀態
4.兩者實例化構造參數解釋
public AutoResetEvent(bool initialState);
true:設置終止狀態。相當於調用了Set(),即首次不會被WaitOne()阻塞,下次執行WaitOne()才會被阻塞
false:設置非終止狀態。遇到WaitOne()立即阻塞所在的一個或多個線程
5. 兩者都只會阻塞WaitOne()所在的線程,WaitOne()可被多個線程調用
二、在哪里創建信號量實例?
一般情況下在工作線程中創建信號量的實例,在其他線程中使用,然后再在工作線程中調用Set(),可以是在非主線程創建實例
三、代碼示例
public class Program
{ //1.AutoResetEvent,調用一次Set()只能繼續一個阻塞線程 //2.AutoResetEvent調用Set()后自動Reset() static void Main(string[] args) { Thread t = null; AutoResetEvent Event = new AutoResetEvent(false); for (int i = 0; i < 2; i++) { t = new Thread(() => { while (true) { //阻塞當前線程 Event.WaitOne(); Console.WriteLine("我是線程:" + Thread.CurrentThread.Name); Thread.Sleep(1000); } }); t.Name = i + ""; t.Start(); } //5秒后允許一個等待的線程繼續。當前允許的是線程1 Thread.Sleep(5000); Event.Set(); //5秒后允許一個等待的線程繼續。當前允許的是線程2 Thread.Sleep(5000); Event.Set(); //PS:如果使用AutoResetEvent的WaitOne()將5個線程阻塞,則需要調用5次Set()才能恢復5;如果再次阻塞時,不需要手動調用Reset(); Console.ReadLine(); } //1.ManualResetEvent,調用一次Set()允許繼續全部阻塞線程,這是和AutoResetEvent的區別 //2.ManualResetEvent調用Set()后需要手動Reset(),將信號 設置為非終止狀態,只有非終止狀態線程中調用WaitOne()才能導所在的致線程阻止。 static void Main2(string[] args) { Thread t = null; //初始化非終止狀態,WaitOne()可以直接阻塞所在的線程 ManualResetEvent Event = new ManualResetEvent(false); for (int i = 0; i < 2; i++) { t = new Thread(() => { while (true) { //阻塞當前線程 Event.WaitOne(); Console.WriteLine("我是線程:" + Thread.CurrentThread.Name);
Event.ReSet(); Thread.Sleep(1000); } }); t.Name = i + ""; t.Start(); } //5秒后允許所有阻塞的線程繼續。 Thread.Sleep(5000); Event.Set(); //PS:如果使用ManualResetEvent將5個線程阻塞,則需要調用1次Set(),將允許所有阻塞的線程繼續執行;如果再次阻塞時,則需要手動調用Reset(); Console.ReadLine(); } }
備注:信號量
