System.Threading.CountdownEvent 是一個同步基元,它在收到一定次數的信號之后,將會解除對其等待線程的鎖定。 CountdownEvent 專門用于以下情況:您必須使用 ManualResetEvent 或 ManualResetEventSlim,并且必須在用信號通知事件之前手動遞減一個變量。 例如,在分叉/聯接方案中,您可以只創建一個信號計數為 5 的 CountdownEvent,然后在線程池上啟動五個工作項,并且讓每個工作項在完成時調用 Signal。 每次調用 Signal 時,信號計數都會遞減 1。 在主線程上,對 Wait 的調用將會阻塞,直至信號計數為零。
CountdownEvent 具有這些附加功能:
?可通過使用取消標記來取消等待操作。
?創建實例之后可以遞增它的信號計數。
?通過調用 Reset 方法,可在 Wait 返回之后重用實例。
?實例公開 WaitHandle 以便與其他 .NET Framework 同步 API(例如 WaitAll)進行集成。——MSDN
1.普通示例
using System;using System.Threading;using System.Threading.Tasks;namespace Consoleapplication18{ class PRogram { static CountdownEvent cde = null; /// <summary> /// 模擬建房子 /// </summary> /// <param name="args"></param> static void Main(string[] args) { //建房子第一期工人 string[] _bhPerson1 = new string[5] { "Yan", "Zhi", "wei", "Do", "Work" }; //建房子第二期工人 string[] _bhPerson2 = new string[3] { "Yan2", "Zhi2", "wei2" }; //建房子第三期工人 string[] _bhPerson3 = new string[3] { "Yan3", "Zhi3", "wei3" }; using (cde = new CountdownEvent(Environment.ProcessorCount))//開始監管,相當于監工 { cde.Reset(_bhPerson1.Length);//設置第一期建造需要5個人 foreach (string person in _bhPerson1) { Task.Factory.StartNew(() => { BuilderHourseStep1(person); }); } cde.Wait();//等待第一期建造完成 Console.WriteLine("-----------------------"); cde.Reset(_bhPerson2.Length);//設置第二期建需要三個人 foreach (string person in _bhPerson2) { Task.Factory.StartNew(() => { BuilderHourseStep2(person); }); } cde.Wait();//等待第二期建造完成 Console.WriteLine("-----------------------"); cde.Reset(_bhPerson3.Length);//設置第三期建需要三個人 foreach (string person in _bhPerson3) { Task.Factory.StartNew(() => { BuilderHourseStep3(person); }); } cde.Wait();//等待第三期建造完成 Console.WriteLine("-----------------------"); } } /// <summary> /// 建房子第一道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep1(string person) { try { Console.WriteLine(string.Format("『{0}』BuilderHourseStep1....", person)); } finally { cde.Signal();//建造完成一點后,通知監工 } } /// <summary> /// 建房子第二道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep2(string person) { try { Console.WriteLine(string.Format("『{0}』BuilderHourseStep2.....", person)); } finally { cde.Signal(); } } /// <summary> /// 建房子第三道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep3(string person) { try { Console.WriteLine(string.Format("『{0}』BuilderHourseStep3.......", person)); } finally { cde.Signal(); } } }}
代碼效果

2.超時演示,延續上面例子,建造房子存在延期的情況,譬如某個工作工作懶散,那么需要給整個一期建造設置一個總的時限。
using System;using System.Threading;using System.Threading.Tasks;namespace ConsoleApplication18{ class Program { static CountdownEvent cde = null; static int overLimitTime = 5000;//第一期工作完成時間 /// <summary> /// 模擬建房子 /// </summary> /// <param name="args"></param> static void Main(string[] args) { try { //建房子第一期工人 string[] _bhPerson1 = new string[5] { "Yan", "Zhi", "wei", "Do", "Work" }; //建房子第二期工人 string[] _bhPerson2 = new string[3] { "Yan2", "Zhi2", "wei2" }; //建房子第三期工人 string[] _bhPerson3 = new string[3] { "Yan3", "Zhi3", "wei3" }; using (cde = new CountdownEvent(Environment.ProcessorCount))//開始監管,相當于監工 { cde.Reset(_bhPerson1.Length);//設置第一期建造需要5個人 Random _workTime = new Random(); foreach (string person in _bhPerson1) { Task.Factory.StartNew(() => { int _doWorkTime = _workTime.Next(3000, 6000);//工人工作時間 BuilderHourseStep1(person, _doWorkTime); }); } bool _bdStep1Result = cde.Wait(overLimitTime); Console.WriteLine(string.Format("第一期建造狀態:{0}.", _bdStep1Result == true ? "完成" : "延時"));//等待第一期建造完成 限制5秒內完成 Console.WriteLine("-----------------------"); if (!_bdStep1Result) return; cde.Reset(_bhPerson2.Length);//設置第二期建需要三個人 foreach (string person in _bhPerson2) { Task.Factory.StartNew(() => { BuilderHourseStep2(person); }); } cde.Wait();//等待第二期建造完成 Console.WriteLine("-----------------------"); cde.Reset(_bhPerson3.Length);//設置第三期建需要三個人 foreach (string person in _bhPerson3) { Task.Factory.StartNew(() => { BuilderHourseStep3(person); }); } cde.Wait();//等待第三期建造完成 Console.WriteLine("-----------------------"); } } catch (Exception ex) { Console.WriteLine(string.Format("Excepton Message: {0}", ex.Message.Trim())); } finally { Console.ReadLine(); } } /// <summary> /// 建房子第一道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep1(string person, int doWorkTime) { bool _isDoWork = doWorkTime < overLimitTime; try { if (_isDoWork) Console.WriteLine(string.Format("『{0}』做事情花費了,{1}s........", person, doWorkTime)); else Console.WriteLine(string.Format("『{0}』做事情太墨跡,花費了{1}s....", person, doWorkTime)); Thread.Sleep(doWorkTime); } finally { if (_isDoWork) cde.Signal();//建造完成后,通知監工 } } /// <summary> /// 建房子第二道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep2(string person) { try { Console.WriteLine(string.Format("『{0}』BuilderHourseStep2.....", person)); } finally { cde.Signal(); } } /// <summary> /// 建房子第三道所需要的工序 /// </summary> /// <param name="person"></param> static void BuilderHourseStep3(string person) { try { Console.WriteLine(string.Format("『{0}』BuilderHourseStep3.......", person)); } finally { cde.Signal(); } } }}
代碼效果


新聞熱點
疑難解答