能夠看到 WaitHandle是 事件(EventWaitHandle)、互斥體(Mutex)、信號量(Sempahore)的父類。spa
WaitHandle咱們最常常使用的方法,並是使用它的靜態方法WaitAll. 咱們會發如今這個WaitHandle裏面只有等待方法,也就是它會阻塞當前線程的執行。線程
那麼如何要解除它對當前線程的阻塞呢,那麼就須要依賴於各個子類的方法了。3d
例如如今有一個這樣的場景,如何在一個方法中,等待全部的線程所有執行完,最後再統計獲得的計算結果呢?code
WaitHandle[] handlers = new WaitHandle[]{ new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false) }; for (var i = 0; i < handlers.Length; i++) { ThreadPool.QueueUserWorkItem(ar => { int index = (int)ar; Thread.Sleep(1000); AppCenter.AppendLog("任務:" + index + "開始執行!"); (handlers[index] as AutoResetEvent).Set(); }, i); } ThreadPool.QueueUserWorkItem(ar => { WaitHandle.WaitAll(handlers); AppCenter.AppendLog("全部任務都已經完成了,我不用再等待了。"); });
這個方法,能夠方便實現兩個線程之間的相互通訊。blog
如何實現兩個線程的相互通訊?事件
EventWaitHandle handleA = new AutoResetEvent(false); EventWaitHandle handleB = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(ar => { AppCenter.AppendLog("A:我是A,我已經開始運行了"); Thread.Sleep(2000); AppCenter.AppendLog("A:我想睡覺了,B你先跑跑吧。"); EventWaitHandle.SignalAndWait(handleB, handleA); AppCenter.AppendLog("A:開始工做ing"); Thread.Sleep(3000); AppCenter.AppendLog("A:這個有點難,問下B"); EventWaitHandle.SignalAndWait(handleB, handleA); AppCenter.AppendLog("A:不錯,今天任務搞定,我也閃人了。"); }); ThreadPool.QueueUserWorkItem(ar => { handleB.WaitOne(); AppCenter.AppendLog("B:我是B,我已經頂替A開始運行了。"); Thread.Sleep(5000); AppCenter.AppendLog("B:個人事情已經作完了,該讓A搞搞了,休息一會。"); EventWaitHandle.SignalAndWait(handleA, handleB); AppCenter.AppendLog("B:hi,A我搞定了,下班了。"); handleA.Set(); });
那麼AutoResetEvent和ManualResetEvent有什麼區別呢?咱們先作個實驗。get
private EventWaitHandle manualEvent = new ManualResetEvent(false); private void ManualResetEvent_Click(object sender, EventArgs e) { AppCenter.CleanLogs(); ThreadPool.QueueUserWorkItem(ar => { int i = 0; while (true) { manualEvent.WaitOne(); //ManualResetEvent的Set()方法,讓事件的終止狀態永遠爲true,讓這裏一直能執行。 i++; //而AutoResetEvent的Set()方法,初始化讓這裏執行一次,而後再次執行時是非終止的。將阻塞原有線程的執行 AppCenter.AppendLog("#" + i.ToString()); Thread.Sleep(1000); } }); } private void button2_Click(object sender, EventArgs e) { manualEvent.Set(); } private void button3_Click(object sender, EventArgs e) { manualEvent.Reset(); }
運行結果it
咱們會發現ManualResetEvent在觸發Set()方法會,解除了原有的線程的 WaitOne方法,會一直打印輸出。class
而當咱們替換爲AutoResetEvent方法時候。object
此時每次只會打印一個輸出。由於它將 事件的狀態設置爲終止後,又變爲了false.
應用場景,若是有多個線程跑,我可否每次控制3個線程一塊兒跑呢。
Semaphore sempore = new Semaphore(0, 3); for (int i = 0; i < 8; i++) { ThreadPool.QueueUserWorkItem(ar => { sempore.WaitOne(); AppCenter.AppendLog("\t第:" +((int)ar).ToString() + "個開始運行."); },i); } ThreadPool.QueueUserWorkItem(ar => { for (int i = 0; i < 3; i++) { AppCenter.AppendLog("第" + (i + 1).ToString() + "批開始執行."); sempore.Release(3); Thread.Sleep(5000); } });
運行結果: