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(); } } }}
代码效果
新闻热点
疑难解答