public class Sample
{ //先执行的线程设置为 true
ManualResetEvent even = new ManualResetEvent(true);
ManualResetEvent odd = new ManualResetEvent(false);
public void Sum()
{
var ta = Task.Run(() => PrintEven(even, odd));
var tb = Task.Run(() => PrintOdd (even,odd));
}
//等待自己的信号,控制另一个线程的信号
public void PrintEven(EventWaitHandle evenHandle, EventWaitHandle oddHandle)
{
string design = "偶数";
for (int i = 0; i <= 20; i++)
{
evenHandle.WaitOne();
if ((i & 1) == 0)
{
Console.WriteLine($"{design}:{i}");
evenHandle.Reset();
oddHandle.Set();
}
}
}
public void PrintOdd(EventWaitHandle evenHandle, EventWaitHandle oddHandle)
{
string design = "奇数";
for (int i = 0; i <= 20; i++)
{
oddHandle.WaitOne();
if ((i & 1) == 1)
{
Console.WriteLine($"{design}:{i}");
oddHandle.Reset();
evenHandle.Set();
}
}
}
}
Event
与信号量一样,事件也是一个系统范围内的资源同步方法。又分为ManualResetEvent,AutoResetEvent,CountdownEvent以及ManualResetEventSlim,在构建对象实例时若传入了name参数,代表这是一个可以跨进程的系统级同步事件。
以 ManualResetEvent 为例,该类有 signaled 和 nonsignaled 两种状态,这两种状态通过实例化对象时的 布尔类型 参数决定,TRUE 就是signaled, False相反
文档中常见的翻译是发出信号的状态和未发出信号的状态,微软官网的机翻是终止状态和非终止状态,还有一些释放线程之类的描述,直观上难以理解。其实就是改变状态而已,还不如英文的好理解。
ManualResetEvent 的基类 EventWaitHandle 中提供了Set() 和Reset() 方法,用于改变状态,Set 将事件修改为 signaled,Reset重置为 nonsignaled
这里说一下Set和Reset,这两个方法是改变了事件的状态,并不是一个瞬时性的动作,也就意味着在调用Set后,调用Reset之前,事件都处于 signaled 状态(AutoResetEvent会自动调用Reset重置事件状态)
WaitHandle 类中提供了众多等待信号的方法,EventWaitHandle 继承自WaitHandle, ManualResetEvent中也可以调用WaitOne等方法。
回头再看一下信号量 Semaphore 的示例,也调用 WaitOne 等待信号,因为它也继承自 Waithandler。