讲师中心 微信公众号
AI工具推荐 视频效率加速

c# Monitor.Wait 和 Monitor.Pulse/PulseAll 的用法和原理

夜芳酱_6224

夜芳酱_6224

发布时间:2026-01-03 10:49:02

|

970人浏览过

|

来源于php中文网

原创

Wait 和 Pulse 实际是“通知+排队+抢锁”三步:Pulse 将等待队列首线程移至就绪队列,当前线程释放锁后,就绪线程竞争锁成功才从 Wait 返回;必须用 while 循环检查条件,且 Wait/Pulse 均需在持锁状态下调用。

c# monitor.wait 和 monitor.pulse/pulseall 的用法和原理

Wait 和 Pulse 不是“唤醒就执行”,而是“通知+排队+抢锁”三步走

很多人以为 Monitor.Pulse() 一调用,等待的线程就立刻继续运行——这是最大误解。实际流程是:持有锁的线程调用 Pulse → 等待队列头部线程被移到就绪队列 → 当前线程释放锁(比如退出 lock 块)→ 就绪队列中某个线程(不一定是刚被 Pulse 的那个)抢到锁 → 它才真正从 Wait() 返回并继续执行。

  • Wait() 必须在已持锁状态下调用,否则抛 SynchronizationLockException
  • Pulse() 和 PulseAll() 同样必须由当前持锁线程调用,否则无效或抛异常
  • 如果 Pulse() 调用时等待队列为空,信号就丢失——下个调用 Wait() 的线程会一直卡住,除非超时
  • 没有“自动重试”机制:线程从 Wait() 返回后,必须手动重新检查条件是否满足(典型模式:while 循环包裹 Wait)

正确写法:永远用 while + Wait,别用 if

这是生产环境最常踩的坑。用 if 判断条件后直接 Wait(),会导致虚假唤醒(spurious wakeup)或条件变更后误执行。正确模式是:

C#
C#

"避开 C# 常见错误——空陷阱、异步陷阱、LINQ 陷阱及资源泄漏。"

下载
lock (syncObj)
{
    while (!conditionIsMet) // ⚠️ 必须用 while!
    {
        Monitor.Wait(syncObj);
    }
    // 此时 conditionIsMet 为 true,安全操作
}
  • 虚假唤醒虽在 .NET 中极少见,但规范要求必须防御;更常见的是:Pulse 后多个线程被唤醒(尤其用了 PulseAll),但只有一个能真正处理,其余必须继续等
  • 条件检查必须在 lock 内完成,否则存在竞态:检查完、Wait 前条件又被其他线程改回 false
  • Monitor.Wait(syncObj, timeout) 返回 false 表示超时,此时仍需检查条件是否满足,不能默认失败

Pulse vs PulseAll:选哪个取决于“通知范围”

Monitor.Pulse() 只唤醒等待队列**头部一个线程**;Monitor.PulseAll() 唤醒**所有等待线程**。选择依据不是“哪个更快”,而是语义:

  • 用 Pulse():适用于“单消费者-单生产者”或“一次只允许一个线程推进”的场景(如队列取一个任务、信号量减一)
  • 用 PulseAll():适用于“状态全局变化,所有等待者都该重新评估”的场景(如缓存刷新完成、批量任务结束、取消标志置位)
  • ⚠️ 注意:PulseAll() 可能引发惊群效应(thundering herd)——大量线程同时争锁,造成短暂 CPU 尖峰;若等待线程多且条件大多不满足,建议改用更细粒度的同步原语(如 BlockingCollection<t></t> 或 SemaphoreSlim)

比 lock 更重,比 async/await 更难调试

Monitor.Wait/Pulse 是纯同步、阻塞式协调,它和 lock 共享同一套 CLR 同步块机制,但复杂度指数上升:

  • 无法与 async/await 混用:Wait() 会阻塞线程,而 await 期望释放线程——二者语义冲突;需要异步等待,请用 SemaphoreSlim.WaitAsync() 或 TaskCompletionSource
  • 死锁风险高:比如 A 线程 Wait 后没被 Pulse,B 线程 Pulse 后自己又 Wait 且没被唤醒,互相卡住
  • 调试困难:VS 的“并行堆栈”窗口能看到线程卡在 Monitor.Wait,但看不到“谁该 Pulse”——必须靠日志或断点确认 Pulse 是否在正确时机、由正确线程发出
  • 现代替代方案优先级:BlockingCollection<t></t>(生产者-消费者)、Channel<t></t>(高吞吐流)、ManualResetEventSlim(简单信号)通常比裸 Monitor 更安全、易读
真实项目里,Monitor.Wait/Pulse 应该是“你已经试过所有高级封装、确认它们不合适之后”的最后手段。它的原理清晰,但每一步都要求你对线程调度、队列状态和条件竞争有精确控制——稍有疏忽,问题就藏得深、复现难。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

354

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6667

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2768

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6667

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2768

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4678

2023.08.10

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

454

2025.11.14

golang channel相关教程
golang channel相关教程

本专题整合了golang处理channel相关教程,阅读专题下面的文章了解更多详细内容。

639

2025.11.17

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

20

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
GDB Reference Card
GDB Reference Card

共0课时 | 0人学习

《Debugging with GDB》用户手册
《Debugging with GDB》用户手册

共0课时 | 0人学习

Valgrind FAQ
Valgrind FAQ

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn