ManualResetEvent
ManualResetEvent
是 .NET 中一种用于线程同步的机制,它允许一个线程通知其他线程某个事件已经发生。ManualResetEvent
是基于内核的同步原语,用于在多线程编程中控制线程的执行顺序。
基本概念
- 信号化和非信号化状态:
- 信号化状态(Set):允许一个或多个等待的线程继续执行。
- 非信号化状态(Reset):阻止线程继续执行,直到进入信号化状态。
ManualResetEvent
的特点是:一旦通过 Set
进入信号状态,所有等待的线程都将继续执行,而不需要再次调用 Set
;除非调用 Reset
,否则它会一直保持信号状态。
常见使用场景
- 线程等待某个事件的发生:一个线程可能需要等待其他线程完成某些工作后再继续执行。
- 控制并发访问:可以用于控制多线程访问共享资源的时机。
ManualResetEvent
的使用方法
1. 初始化
ManualResetEvent
有一个构造函数,接收一个布尔值参数,用于指示它的初始状态:
true
表示初始状态为信号化。false
表示初始状态为非信号化。
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
2. 等待信号化状态
线程通过调用 WaitOne()
方法来等待 ManualResetEvent
进入信号化状态。如果 ManualResetEvent
已经处于信号化状态,WaitOne()
方法会立即返回;如果是非信号化状态,线程将被阻塞,直到调用 Set()
。
manualResetEvent.WaitOne(); // 等待事件进入信号状态
3. 设置信号化状态
通过调用 Set()
方法,ManualResetEvent
进入信号化状态,所有调用 WaitOne()
阻塞的线程将被释放继续执行。
manualResetEvent.Set(); // 将事件设置信号化
4. 重置为非信号化状态
调用 Reset()
方法将 ManualResetEvent
设置为非信号化状态,这样后续调用 WaitOne()
的线程会再次被阻塞。
manualResetEvent.Reset(); // 将事件重置为非信号化
示例代码
以下是一个简单的例子,展示了如何使用 ManualResetEvent
进行线程同步:
using System;
using System.Threading;
class Program
{
static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
// 启动两个线程
new Thread(ThreadWork).Start();
new Thread(ThreadWork).Start();
Console.WriteLine("主线程等待2秒后设置事件信号化...");
Thread.Sleep(2000);
// 设置信号化,允许所有等待的线程继续执行
manualResetEvent.Set();
Console.WriteLine("主线程等待1秒后重置事件为非信号化...");
Thread.Sleep(1000);
manualResetEvent.Reset();
Console.ReadLine();
}
static void ThreadWork()
{
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 等待信号...");
manualResetEvent.WaitOne(); // 等待信号
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 已收到信号,继续执行...");
}
}
输出结果:
主线程等待2秒后设置事件信号化...
线程 3 等待信号...
线程 4 等待信号...
线程 3 已收到信号,继续执行...
线程 4 已收到信号,继续执行...
主线程等待1秒后重置事件为非信号化...
小结
- ManualResetEvent 是一种线程同步机制,允许多个线程等待某个事件的发生。
- 通过调用
Set()
将事件设置信号化,所有等待的线程将被释放;通过Reset()
重新进入非信号化状态。 - 与
AutoResetEvent
不同的是,ManualResetEvent
保持信号化状态,允许多个线程通过,而不是每次只释放一个线程。