C# AutoResetEvent类 使用详解
2026/9/3 11:08:21 网站建设 项目流程

总目录


前言

在C#中,AutoResetEvent是一个用于线程同步的关键类,它位于System.Threading命名空间下。它的核心功能是通过信号机制控制线程的执行顺序,允许一个或多个线程等待某个信号后再继续运行。常用于需要线程间通信的场景。


一、核心概念

本文中所描述的 有信号状态、终止状态、触发状态 意义相同,都是同一种状态的不同名称

AutoResetEvent 理解成 一扇门 true 开门信号,false 关门信号,当有开门信号的时候 就开门,反之,则关门

二、基本用法

1. 构造函数

varautoEvent=newAutoResetEvent(initialState:false);// 初始无信号/或称 未触发

2. 关键方法

注意

3. 主要场景

场景描述
生产者-消费者队列生产线程入队一个任务后Set(),消费者线程WaitOne()等待,每次只唤醒一个消费者处理任务。
等待异步操作完成主线程启动一个异步操作,用AutoResetEvent等待操作完成,操作完成后Set()通知。
控制线程池中任务逐个执行多个工作线程等待信号,主控线程逐步释放每个任务。
实现简单的锁(但通常用lock更好)用于一次性许可的互斥,但性能较差。
模拟“门禁”一次只允许一个线程进入某个阶段,例如游戏回合制。

三、 示例

示例 1:线程等待主线程信号

usingSystem.Threading;classProgram{staticAutoResetEventautoEvent=newAutoResetEvent(false);staticvoidMain(){Threadworker=newThread(DoWork);worker.Start();// 主线程触发信号Thread.Sleep(2000);Console.WriteLine("主线程发送信号");autoEvent.Set();// 唤醒工作线程}staticvoidDoWork(){Console.WriteLine("工作线程等待信号...");autoEvent.WaitOne();// 阻塞直到信号到来Console.WriteLine("工作线程继续执行");}}

输出

工作线程等待信号... 主线程发送信号 工作线程继续执行

示例 2:主线程等待工作线程信号

usingSystem;usingSystem.Threading;classProgram{staticAutoResetEvent_autoResetEvent=newAutoResetEvent(false);staticvoidMain(string[]args){// 启动一个新线程Threadt=newThread(Work);t.Start();Console.WriteLine("主线程等待...");// 主线程等待_autoResetEvent.WaitOne();Console.WriteLine("主线程继续执行");}staticvoidWork(){Console.WriteLine("工作线程正在工作...");// 模拟一些工作Thread.Sleep(1000);Console.WriteLine("工作完成,通知主线程");// 发送信号,允许等待的线程继续_autoResetEvent.Set();}}

在这个例子中,主线程调用 _autoResetEvent.WaitOne(); 等待,而工作线程在完成任务后调用 _autoResetEvent.Set(); 通知主线程继续执行。

输出

主线程等待...工作线程正在工作...工作完成,通知主线程 主线程继续执行

示例3:线程执行控制

classProgram{// 控制第一个线程// 第一个线程开始时,AutoResetEvent 处于终止状态,无需等待信号privatestaticAutoResetEventoneResetEvent=newAutoResetEvent(true);// 控制第二个线程// 第二个线程开始时,AutoResetEvent 处于非终止状态,需要等待信号privatestaticAutoResetEventtwoResetEvent=newAutoResetEvent(false);staticvoidMain(string[]args){newThread(DoOne).Start();newThread(DoTwo).Start();Console.ReadKey();}publicstaticvoidDoOne(){while(true){Console.WriteLine("\n① 按下任意键,我就让DoTwo运行");Console.ReadKey();twoResetEvent.Set();oneResetEvent.Reset();// 等待 DoTwo() 给我信号oneResetEvent.WaitOne();Console.ForegroundColor=ConsoleColor.Green;Console.WriteLine("\n DoOne() 执行");Console.ForegroundColor=ConsoleColor.White;}}publicstaticvoidDoTwo(){while(true){Thread.Sleep(TimeSpan.FromSeconds(1));// 等待 DoOne() 给我信号twoResetEvent.WaitOne();Console.ForegroundColor=ConsoleColor.Yellow;Console.WriteLine("\n DoTwo() 执行");Console.ForegroundColor=ConsoleColor.White;Console.WriteLine("\n② 按下任意键,我就让DoOne运行");Console.ReadKey();oneResetEvent.Set();twoResetEvent.Reset();}}}

代码分析

四、高级用法

1. 超时等待

boolsignaled=autoEvent.WaitOne(TimeSpan.FromSeconds(5));// 最多等待5秒if(!signaled){Console.WriteLine("等待超时");}

2. 多线程竞争

// 多个线程等待同一个事件for(inti=0;i<3;i++){newThread(()=>{autoEvent.WaitOne();Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}被唤醒");}).Start();}// 需要调用 Set() 三次才能唤醒所有线程autoEvent.Set();// 唤醒第一个线程autoEvent.Set();// 唤醒第二个线程autoEvent.Set();// 唤醒第三个线程

5、 注意事项

  1. 资源释放:用完需调用Dispose()或使用using块(AutoResetEvent继承自WaitHandle)。
  2. 竞态条件:确保Set()WaitOne()的调用顺序合理,避免死锁。
  3. 自动重置导致“丢失信号”:如果 Set() 发生时没有线程在等待,则该信号会丢失,后续 WaitOne() 会继续阻塞。确保至少有一个线程在等待,或者使用 WaitOne(0) 检查状态。
  4. 避免死锁:若持有 AutoResetEvent 的线程未 Set(),等待线程将永久阻塞。建议使用超时重载 WaitOne(int millisecondsTimeout)。
  5. 不适用于“广播”:要唤醒所有线程,应使用 ManualResetEvent。
  6. 与 ManualResetEvent 的区别
    • AutoResetEvent自动重置信号,适合一次唤醒一个线程。
    • ManualResetEvent需手动调用Reset(),适合广播多个线程。

六、总结

选择建议:

掌握 AutoResetEvent,能让你更好地控制线程协作,但在现代 C# 中,更推荐使用 Task 和 async/await 来简化异步流程,仅在需要底层同步时使用这些经典基元。


结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
自动线程通知 AutoResetEvent

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询