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。