ManualResetEvent 和 AutoResetEvent 是两种线程同步的方案。
他们可以通过调用 WaitOne()
方法阻塞当前线程,直到其他线程上调用了 Set()
方法。
例子
详细的使用方法如下所示:
1 | using System; |
运行结果如下:
1 | task1 : Before WaitOne() |
使用方法
首先需要初始化一个 ManualResetEvent
或是 AutoResetEvent
。构造函数带一个参数,类型为 bool ,表示初始状态是否设置为终止。这个状态之后可以通过 Set()
和 Reset()
方法来改变。
换句话说,类似于 Event 中有一个开关,表示是否 WaitOne
时是否阻塞。
如果初始化为 true ,或是调用过 Set()
,那么这个开关就是打开的状态,当 Event 调用 WaitOne()
方法时,线程不会暂停,会继续执行下去。
而当初始化为 false ,或是调用过 Reset()
时,那么这个开关就是关闭的状态,当 Event 调用 WaitOne()
方法时线程会被阻塞,直到有其他线程通过 Set()
打开了开关。
ManualResetEvent 与 AutoResetEvent 的区别
ManualResetEvent
ManualResetEvent
的 Set()
为打开,Reset()
为关闭。一旦打开,所有阻塞在 WaitOne()
的线程都会继续执行。
1 | using System; |
运行结果:
1 | task2 : Before WaitOne() |
AutoResetEvent
AutoResetEvent
的 Set()
和 Reset()
与 ManualResetEvent
一致。不同的是,每有一个阻塞在 WaitOne()
的线程由于开关打开而继续执行,都会自动回弹开关。(这也就是 AutoReset 的含义)
1 | using System; |
运行结果:
1 | task1 : Before WaitOne() |
保持阻塞,无法继续执行。
原因是 task1 被唤醒的同时关闭了开关, task2 无法通过。
结论
需要唤醒的线程只有一个时,两种没有区别。
会有多个线程同时等待,而每次只希望唤醒一个线程时,用 AutoResetEvent ,
希望一次唤醒所有线程永久可以通过时,用 ManualResetEvent 。