AutoResetEvent和ManualResetEvent是.NET Framework中用于同步多线程操作的两个非常重要的类。它们都属于System.Threading命名空间,主要用于在多个线程之间实现信号量或互斥锁的功能。本文将深入探讨这两个类的知识和原理,并给出必要的实例和使用场景。
AutoResetEvent
AutoResetEvent是一个非阻塞的事件类,它允许一个或多个等待线程继续执行。当AutoResetEvent的Set方法被调用时,所有等待在该事件上的线程都将被唤醒。当AutoResetEvent的Reset方法被调用时,该事件将被重置,所有等待在该事件上的线程都将被阻止。
AutoResetEvent的主要优点是它不会阻止调用线程,因为它是非阻塞的。这意味着在调用Set或Reset方法时,不需要使用锁来保护事件对象。
实例:
static AutoResetEvent autoEvent = new AutoResetEvent(false);
static void Main()
{
Thread thread1 = new Thread(DoWork);
thread1.Start();
Console.WriteLine("主线程等待子线程完成...");
autoEvent.WaitOne(); // 等待子线程完成
Console.WriteLine("子线程已完成,主线程继续执行。");
}
static void DoWork()
{
Console.WriteLine("子线程开始工作...");
Thread.Sleep(2000); // 模拟耗时操作
Console.WriteLine("子线程工作完成。");
autoEvent.Set(); // 设置事件,唤醒等待的线程
}
运行结果:
使用场景:AutoResetEvent适用于需要多个线程同时执行的场景,例如生产者-消费者模型、任务队列等。在这些场景中,AutoResetEvent可以确保只有一个线程在执行关键部分的代码,而其他线程则在等待信号。
ManualResetEvent
ManualResetEvent是一个阻塞的事件类,它允许一个或多个等待线程继续执行。与AutoResetEvent不同,ManualResetEvent需要手动重置才能使等待的线程继续执行。当ManualResetEvent的Set方法被调用时,所有等待在该事件上的线程都将被唤醒。多个线程可以通过调用ManualResetEvent对象的WaitOne方法进入等待或阻塞状态。当控制线程调用Set()方法,所有等待线程将恢复并继续执行。
ManualResetEvent的主要优点是它可以更好地控制线程的执行顺序。通过手动重置事件,可以实现更复杂的同步逻辑。
实例:
class Program
{
static void Main()
{
ManualResetEvent manualEvent = new ManualResetEvent(false);
int threadCount = 5;
Thread[] threads = new Thread[threadCount];
Console.WriteLine("{0} 主线程开始Set。", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(DoWork);
threads[i].Start(manualEvent);
}
manualEvent.Set();
manualEvent.Reset();
Console.WriteLine();
Thread.Sleep(2000);
manualEvent.Set();
for (int i = 0; i < threadCount; i++)
{
threads[i].Join(); // 等待所有线程完成
}
Console.WriteLine("所有线程已完成。");
}
static void DoWork(object state)
{
var manualEvent = (ManualResetEvent)state;
Console.WriteLine("{0} 线程 {1} 收到事件,开始执行任务1。", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Thread.CurrentThread.ManagedThreadId);
manualEvent.WaitOne();
Console.WriteLine("{0} 线程 {1} 收到事件,开始执行任务2。", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Thread.CurrentThread.ManagedThreadId);
manualEvent.WaitOne();
}
}
运行结果:
使用场景:ManualResetEvent适用于需要多个线程按照特定顺序执行的场景,例如任务链、并行处理等。在这些场景中,ManualResetEvent可以确保每个线程都按照预期的顺序执行关键部分的代码