EventWaitHandle 是 .NET 中用于线程同步的一个核心基类,它封装了 Windows 操作系统中的 “事件内核对象(Event Kernel Object)”,用于在多个线程之间传递信号、协调执行顺序。

AutoResetEventManualResetEvent 都是 EventWaitHandle 的派生类。理解 EventWaitHandle 有助于你更灵活地使用或自定义事件同步机制。


🧱 一、什么是 EventWaitHandle?

EventWaitHandle 表示一个“线程同步事件”,它有两种状态:

  • 非信号状态(nonsignaled):调用 WaitOne() 的线程会被阻塞。
  • 信号状态(signaled):调用 WaitOne() 的线程可以立即继续执行。

你可以通过 Set() 将其置为信号状态,通过 Reset() 置为非信号状态。


🔁 二、EventWaitHandle 的两种模式

EventWaitHandle 的行为由构造函数中的 EventResetMode 枚举决定:

public enum EventResetMode
{
    AutoReset,   // 自动重置模式 → 相当于 AutoResetEvent
    ManualReset  // 手动重置模式 → 相当于 ManualResetEvent
}

✅ 创建方式:

// 等价于 new AutoResetEvent(false)
var auto = new EventWaitHandle(
    initialState: false, 
    mode: EventResetMode.AutoReset
);

// 等价于 new ManualResetEvent(false)
var manual = new EventWaitHandle(
    initialState: false, 
    mode: EventResetMode.ManualReset
);

💡 所以:
AutoResetEventnew EventWaitHandle(false, EventResetMode.AutoReset)
ManualResetEventnew EventWaitHandle(false, EventResetMode.ManualReset)


🛠 三、核心方法与属性

方法/属性说明
WaitOne()阻塞当前线程,直到事件变为信号状态
WaitOne(int timeout)带超时的等待(毫秒),超时返回 false
Set()将事件设为信号状态
Reset()将事件设为非信号状态
Close() / Dispose()释放底层操作系统句柄(推荐 using 或显式释放)

🔐 四、底层原理(Windows 内核)

  • EventWaitHandle 封装了 Windows API 中的 CreateEvent 内核对象。
  • 它是一个 内核模式同步对象(Kernel-mode synchronization object),因此:
    • 可跨进程共享(通过命名事件)
    • 性能开销比用户模式同步(如 MonitorSpinLock)大
    • 但功能更强(支持超时、跨进程等)

🌐 五、高级用法:命名事件(跨进程同步)

EventWaitHandle 支持命名事件,可用于不同进程间的线程同步

示例:确保程序单实例运行

static void Main()
{
    bool createdNew;
    using var mutex = new Mutex(true, "MyAppSingletonMutex", out createdNew);
    // 但也可以用命名 EventWaitHandle 实现类似逻辑

    using var eventHandle = new EventWaitHandle(
        false,
        EventResetMode.ManualReset,
        "Global\\MyAppReadyEvent", // 名称,"Global\" 表示全局命名空间
        out createdNew
    );

    if (createdNew)
    {
        Console.WriteLine("我是第一个实例,正在初始化...");
        Thread.Sleep(3000);
        eventHandle.Set(); // 通知其他实例我已就绪
    }
    else
    {
        Console.WriteLine("已有实例运行,等待其就绪...");
        eventHandle.WaitOne(); // 等待第一个实例发出信号
        Console.WriteLine("主实例已就绪,继续执行...");
    }
}

⚠️ 注意:

  • 名称在系统范围内必须唯一
  • 在 Windows 上,普通用户默认只能访问 Local\ 命名空间;需要管理员权限才能使用 Global\
  • Linux/macOS(.NET Core+)也支持命名事件,但实现依赖于平台(如 POSIX 命名信号量)

🔄 六、与 WaitHandle.WaitAny / WaitAll 配合使用

EventWaitHandle 继承自 WaitHandle,因此可以和 WaitHandle.WaitAnyWaitHandle.WaitAll 一起使用,实现多事件等待

示例:等待多个任务中的任意一个完成

var event1 = new EventWaitHandle(false, EventResetMode.AutoReset);
var event2 = new EventWaitHandle(false, EventResetMode.AutoReset);
var events = new WaitHandle[] { event1, event2 };

// 启动两个任务
Task.Run(() => {
    Thread.Sleep(1000);
    event1.Set();
});

Task.Run(() => {
    Thread.Sleep(2000);
    event2.Set();
});

// 等待任意一个事件触发
int index = WaitHandle.WaitAny(events);
Console.WriteLine($"事件 {index} 先完成!");

✅ 这在异步协调、超时控制、多条件触发等场景非常有用。


⚖️ 七、性能与适用场景建议

场景推荐方案
简单线程唤醒(单次)AutoResetEventEventWaitHandle(AutoReset)
广播唤醒所有线程ManualResetEvent
跨进程同步命名的 EventWaitHandle
高性能、低延迟(同进程)优先考虑 Monitor.Wait/PulseTaskCompletionSourceSemaphoreSlim
需要等待多个事件WaitHandle.WaitAny / WaitAll + EventWaitHandle

❗ 注意:由于 EventWaitHandle 涉及内核切换,每秒数千次以上的高频同步应避免使用它


🧪 八、完整示例:生产者-消费者(使用 EventWaitHandle)

class Program
{
    static EventWaitHandle _itemAdded = new EventWaitHandle(false, EventResetMode.AutoReset);
    static Queue<int> _queue = new Queue<int>();
    static readonly object _lock = new object();

    static void Main()
    {
        new Thread(Consumer).Start();
        new Thread(Producer).Start();

        Console.ReadKey();
    }

    static void Producer()
    {
        for (int i = 0; i < 5; i++)
        {
            lock (_lock)
            {
                _queue.Enqueue(i);
                Console.WriteLine($"生产: {i}");
            }
            _itemAdded.Set(); // 通知消费者
            Thread.Sleep(500);
        }
    }

    static void Consumer()
    {
        while (true)
        {
            _itemAdded.WaitOne(); // 等待有新项
            lock (_lock)
            {
                if (_queue.Count > 0)
                {
                    int item = _queue.Dequeue();
                    Console.WriteLine($"消费: {item}");
                }
            }
        }
    }
}

✅ 九、总结

特性说明
本质封装 Windows 事件内核对象的 .NET 类
两种模式AutoReset(过一人自动关) vs ManualReset(需手动关)
继承关系EventWaitHandleWaitHandleMarshalByRefObjectobject
关键能力线程阻塞/唤醒、超时控制、跨进程同步、多事件等待
替代方案高频场景用 SemaphoreSlimTaskChannels 等更现代的并发原语

💡 记住
EventWaitHandle 是底层而强大的同步工具,适合中低频、需要精确控制或跨进程的场景。
日常开发中,若无特殊需求,优先考虑更高层的抽象(如 Taskasync/awaitBlockingCollection)。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐