You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:33:57