如果预计操作的等待的时间非常短,可以考虑使用轻量级的手动重置事件,ManualResetEventSlim。它可以发出信号和等待事件。从名称和使用方式上看,它主要是提供以人为本的操作方式,在基于人对程序运行过程非常了解的情况下,由人控制整个同步的过程。
ManualResetEventSlim 提供了3个常用的方法和3个只读的属性。
构造函数:
方法:
属性:
程序示例:在这个例子中使用了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);
程序示例:在这个例子中任务1会等待5秒后在设置Event,但任务2,3的超时时间为2秒。
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
{
System.Threading.Thread.Sleep(5000);
m_Worker2Event.Set();
}
}
}
private static void Work2(int TaskID)
{
int i = 0;
string log = "";
if (!m_Worker2Event.Wait(2000))
{
Console.WriteLine("Task 2 wait for event TIME OUT!!");
return;
}
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 = "";
if (!m_Worker3Event.Wait(2000))
{
Console.WriteLine("Task 3 wait for event TIME OUT!!");
return;
}
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();
}
}
}
可以注意到其实Task 1只是阻塞了Task2,但Task3也受到了超时的影响。超时机制在系统中的传播会对整个程序造成一定的影响。
好的方面:帮助系统所有模块了解到系统中出现了某些异常,要采取措施了。
坏的方面:有些模块对于其他模块的超时并没有相应的准备,直接导致一连串的异常的反应,系统崩溃。
如果需要实现跨进程的同步,这时可以使用ManualResetEvent。ManualResetEvent和ManualResetEventSlim有一定的区别,比如它没有IsSet属性。
方法:
ManualResetEvent的使用方式和ManualResetEventSlim还是基本一致的。
原文地址:http://blog.csdn.net/wangzhiyu1980/article/details/45865779