C# 并行编程 之 轻量级手动重置事件的使用

时间:2021-12-28 04:05:39

如果预计操作的等待的时间非常短,可以考虑使用轻量级的手动重置事件,ManualResetEventSlim。它可以发出信号和等待事件。从名称和使用方式上看,它主要是提供以人为本的操作方式,在基于人对程序运行过程非常了解的情况下,由人控制整个同步的过程。

ManualResetEventSlim 提供了3个常用的方法和3个只读的属性。

构造函数:

ManualResetEventSlim():使用无信号初始状态初始化 ManualResetEventSlim 类的新实例。

ManualResetEventSlim(Boolean):使用一个指示是否将初始状态设置为有信号的布尔值初始化 
ManualResetEventSlim 类的新实例。

ManualResetEventSlim(Boolean, Int32):使用一个指示是否将初始状态设置为有信号和指定自旋计数的布尔值初始化 ManualResetEventSlim 类的新实例。

方法:

Reset:将事件置为false (取消设置/取消信号)

Set:将事件置为true(设置/发出信号),如果有任务在等待,这时它会得到这个信号并解除阻塞。

Wait:阻塞当前任务或线程,直到另外的线程发出信号。

属性:

IsSet:一个bool值,表明事件是否被设置。

SpinCount:进入内核等待前要执行自旋的次数。

WaitHandle:提供了操作系统对象WaitHandle的访问。通过这个对象可以等待对共享资源的排他访问。

程序示例:在这个例子中使用了ManualResetEventSlim,它使得Task1,2,3变成了顺序运行。

using System; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Sample5_7_manualreseteventslim { class Program { private static int _TaskNum = 3; private static Task[] _Tasks; private static StringBuilder _StrBlder; private const int RUN_LOOP = 10; private static ManualResetEventSlim m_Worker2Event; private static ManualResetEventSlim m_Worker3Event; private static void Work1(int TaskID) { int i = 0; string log = ""; while (i < RUN_LOOP) { log = String.Format("Time: {0} Task : #{1} Value: {2} =====\n", DateTime.Now.TimeOfDay, TaskID, i); i++; try { _StrBlder.Append(log); } finally { m_Worker2Event.Set(); } } } private static void Work2(int TaskID) { int i = 0; string log = ""; m_Worker2Event.Wait(); while ((i < RUN_LOOP) && (m_Worker2Event.IsSet)) { log = String.Format("Time: {0} Task : #{1} Value: {2} *****\n", DateTime.Now.TimeOfDay, TaskID, i); i++; try { _StrBlder.Append(log); } finally { m_Worker3Event.Set(); } } } private static void Work3(int TaskID) { int i = 0; string log = ""; m_Worker3Event.Wait(); while ((i < RUN_LOOP) && (m_Worker3Event.IsSet)) { log = String.Format("Time: {0} Task : #{1} Value: {2} ~~~~~\n", DateTime.Now.TimeOfDay, TaskID, i); i++; try { _StrBlder.Append(log); } finally { } } } static void Main(string[] args) { _Tasks = new Task[_TaskNum]; _StrBlder = new StringBuilder(); m_Worker2Event = new ManualResetEventSlim(false, 100); m_Worker3Event = new ManualResetEventSlim(false, 100); _Tasks[0] = Task.Factory.StartNew((num) => { var taskid = (int)num; Work1(taskid); }, 0); _Tasks[1] = Task.Factory.StartNew((num) => { var taskid = (int)num; Work2(taskid); }, 1); _Tasks[2] = Task.Factory.StartNew((num) => { var taskid = (int)num; Work3(taskid); }, 2); var finalTask = Task.Factory.ContinueWhenAll(_Tasks, (tasks) => { Task.WaitAll(_Tasks); Console.WriteLine("=========================================================="); Console.WriteLine("All Phase is completed"); Console.WriteLine("=========================================================="); Console.WriteLine(_StrBlder); }); try { finalTask.Wait(); } catch (AggregateException aex) { Console.WriteLine("Task failed And Canceled" + aex.ToString()); } finally { m_Worker2Event.Dispose(); m_Worker3Event.Dispose(); } Console.ReadLine(); } } }

使用超时和取消

超时机制对于任务的同步是非常必要的,这里也提供了用户设置超时的方法。 
ManualResetEventSilm.Wait(int TIME_OUT);