在C#中如何等待AutoResetEvent触发或线程结束的先发生事件?
在C#中等待AutoResetEvent或线程结束的正确姿势
你碰到的问题很典型:Thread类型本身并不继承WaitHandle,所以没法直接塞进WaitHandle.WaitAny的参数数组里。要解决这个问题,关键是把“线程结束”这个事件包装成一个可被等待的WaitHandle对象,这样就能和你的AutoResetEvent一起,用WaitHandle.WaitAny来监听先发生的那个事件了。下面给你几种实用的实现方案:
方案一:用ManualResetEvent跟踪线程结束
这是最直接的传统解决方案,手动创建一个ManualResetEvent,在线程的执行逻辑末尾(包括异常分支)触发这个事件,这样线程结束时就会同步通知等待逻辑。
示例代码:
using System; using System.Threading; class Example { AutoResetEvent _stopEvent = new AutoResetEvent(false); public void Start() { // 创建用于跟踪线程结束的事件,初始状态为未触发 var threadCompletedEvent = new ManualResetEvent(false); var t = new Thread(() => { try { // 这里编写线程的业务逻辑 Console.WriteLine("线程启动,开始执行任务"); Thread.Sleep(5000); // 模拟耗时操作 Console.WriteLine("线程任务执行完毕"); } finally { // 无论线程正常结束还是异常退出,都触发结束事件 threadCompletedEvent.Set(); } }); t.Start(); // 等待_stopEvent或线程结束事件中的任意一个 WaitHandle[] handles = new WaitHandle[] { _stopEvent, threadCompletedEvent }; int result = WaitHandle.WaitAny(handles); switch(result) { case 0: Console.WriteLine("_stopEvent被触发"); break; case 1: Console.WriteLine("线程已结束"); break; } // 释放资源,避免内存泄漏 threadCompletedEvent.Dispose(); _stopEvent.Dispose(); } }
方案二:用Task替代Thread(推荐现代.NET环境)
如果你的项目基于.NET Core/.NET 5+,更推荐用Task替代Thread——Task天生支持灵活的等待机制,能轻松和现有等待逻辑适配。
基于WaitHandle.WaitAny的实现:
using System; using System.Threading; using System.Threading.Tasks; class Example { AutoResetEvent _stopEvent = new AutoResetEvent(false); public void Start() { var task = Task.Run(() => { Console.WriteLine("Task启动,开始执行任务"); Thread.Sleep(5000); // 模拟耗时操作 Console.WriteLine("Task任务执行完毕"); }); // 获取Task对应的WaitHandle(.NET Core/.NET 5+及旧.NET Framework均支持) var taskWaitHandle = task.WaitHandle; WaitHandle[] handles = new WaitHandle[] { _stopEvent, taskWaitHandle }; int result = WaitHandle.WaitAny(handles); switch(result) { case 0: Console.WriteLine("_stopEvent被触发"); break; case 1: Console.WriteLine("Task已结束"); break; } _stopEvent.Dispose(); // Task的WaitHandle由框架自动管理,无需手动释放 } }
更优雅的Task.WhenAny异步实现:
如果不需要依赖WaitHandleAPI,用Task.WhenAny更符合现代异步编程风格:
using System; using System.Threading; using System.Threading.Tasks; class Example { AutoResetEvent _stopEvent = new AutoResetEvent(false); public async Task StartAsync() { var task = Task.Run(() => { Console.WriteLine("Task启动,开始执行任务"); Thread.Sleep(5000); Console.WriteLine("Task任务执行完毕"); }); // 把_stopEvent的等待逻辑包装成Task var stopEventTask = Task.Run(() => _stopEvent.WaitOne()); // 等待任意一个Task完成 var completedTask = await Task.WhenAny(task, stopEventTask); if (completedTask == stopEventTask) { Console.WriteLine("_stopEvent被触发"); } else { Console.WriteLine("Task已结束"); } _stopEvent.Dispose(); } }
注意事项
- 所有
WaitHandle类型的对象都要记得正确释放(用using语句或手动调用Dispose),避免资源泄漏。 - 线程的结束事件一定要放在
finally块中触发,确保线程无论正常退出还是抛出异常,都能通知等待逻辑。
内容的提问来源于stack exchange,提问作者gindi
相关产品推荐
相关产品推荐

