ManualResetEvent 初始化通常用 false,表示初始未触发、WaitOne() 阻塞;true 则立即返回。WaitOne() 是内核级睡眠,不耗 CPU,支持超时和取消。Set() 唤醒所有等待线程,Reset() 需手动调用。现代异步编程推荐 TaskCompletionSource。

ManualResetEvent 初始化时该用 true 还是 false
取决于你希望线程初始状态是“已就绪”还是“需等待”。new ManualResetEvent(false) 表示初始未触发,调用 WaitOne() 会阻塞;new ManualResetEvent(true) 则初始已触发,WaitOne() 立即返回。多数场景用 false,比如等待某个初始化完成后再继续执行。
WaitOne() 阻塞线程但不释放 CPU 资源
WaitOne() 是内核级等待,线程进入睡眠状态,不消耗 CPU。它比轮询(如 while(!flag) Thread.Sleep(1))高效得多。注意以下几点:
- 可传入超时毫秒数,如
evt.WaitOne(5000),超时返回false,避免永久挂起 - 若在 UI 线程中调用,会导致界面冻结,应改用
await Task.Run(() => evt.WaitOne())或配合异步模式 - 支持取消令牌:用
WaitOne(CancellationToken)可响应外部取消请求
Set() 和 Reset() 的行为容易被误解
Set() 将事件置为“已触发”,所有正在或之后调用 WaitOne() 的线程都会立即通过;Reset() 手动将其恢复为“未触发”。关键点:
- 没有自动重置机制——不像
AutoResetEvent,一次Set()可唤醒多个等待线程 - 如果忘记调用
Reset(),后续所有WaitOne()都不会阻塞,可能引发逻辑错误 - 多次调用
Set()和只调一次效果相同;重复Reset()也无害,但无意义
替代方案:async/await 下更推荐使用 TaskCompletionSource
在现代 C# 异步编程中,ManualResetEvent 属于同步原语,与 async 不天然兼容。若需 awaitable 等待信号,优先用:
var tcs = new TaskCompletionSource<bool>(); // 触发信号 tcs.TrySetResult(true); // 等待 await tcs.Task;
它不绑定线程上下文,支持取消、超时组合,且无 Dispose 忘记调用导致句柄泄漏的风险。只有在必须跨进程/跨线程精确控制内核同步,或与旧代码交互时,才坚持用 ManualResetEvent。


















