1.概要
ManualResetEvent
用于在多个线程之间进行通信。它可以控制线程的执行顺序和时间,使得一个或多个线程等待某个条件成立(或者说事件发生)
主要特点:
- 两种状态:
ManualResetEvent
具有两种状态 - 信号和非信号。调用Set()
方法将事件设置为信号状态,调用Reset()
方法将事件设置为非信号状态。 - 阻塞或释放多个线程:在事件为非信号状态时,调用
WaitOne()
方法的线程将被阻塞。当事件转换为信号状态时,所有等待该事件的线程都将继续执行。 - 手动重置:与
AutoResetEvent
不同,ManualResetEvent
不会在释放一个等待的线程后自动重置为非信号状态。相反,它会保持信号状态,直到明确调用Reset()
方法。 - 跨线程通信:
ManualResetEvent
可以用于不同线程之间的通信。一个线程可以等待一个事件,而另一个线程可以设置或重置该事件。 - 简单易用:
ManualResetEvent
类的 API 非常简单直接,只需要几个方法就能实现线程间的有效同步。 - 线程池兼容:
ManualResetEvent
可以与 .NET 的线程池 (ThreadPool
) 结合使用,以便更有效地管理和控制线程资源。
优点
- 线程同步:
ManualResetEvent
提供了一种有效的方式来同步多个线程。你可以使用它来确保一个或多个线程在其他工作完成之前不会继续进行。 - 灵活性:与
AutoResetEvent
相比,ManualResetEvent
允许多个等待的线程在事件被设为信号状态后同时继续进行。这是因为ManualResetEvent
在被手动重置之前会保持信号状态,而AutoResetEvent
在释放一个等待的线程后会自动回到非信号状态。
缺点
- 手动控制:
ManualResetEvent
需要手动重置,这可能会导致错误,例如如果忘记重置事件,那么所有调用WaitOne()
的线程将立即继续执行,即使预期应该阻塞他们。 - 无法传递额外信息:
ManualResetEvent
只提供二元(信号/非信号)的同步机制,并不能传递更为复杂的状态信息。对于需要传递更多数据或状态信息的场景,可能需要使用更为复杂的同步结构如Monitor
,Mutex
,Semaphore
等。
2.详细内容
代码语言:javascript复制using System;
using System.Threading;
class Program
{
private static ManualResetEvent manualEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
Thread thread1 = new Thread(ThreadProc);
thread1.Name = "Thread1";
thread1.Start();
Thread thread2 = new Thread(ThreadProc);
thread2.Name = "Thread2";
thread2.Start();
Console.WriteLine("Waiting for threads to complete.");
manualEvent.Set(); // Signal that work can be done.
thread1.Join();
thread2.Join();
Console.WriteLine("All threads have completed.");
}
static void ThreadProc()
{
string name = Thread.CurrentThread.Name;
Console.WriteLine($"{name} waits on ManualResetEvent.");
manualEvent.WaitOne(); // Wait for the signal.
Console.WriteLine($"{name} receives a signal to proceed.");
// Do some work...
}
}