是,但仅唤醒当前阻塞在cond.wait中的goroutine;未调用wait或wait后才启动的goroutine不会被唤醒,且唤醒后必须在mutex保护下重新检查条件。

Cond.Broadcast 会唤醒所有等待的 goroutine 吗?
会,但有个关键前提:Cond.Broadcast 只唤醒当前在 Cond.Wait 中阻塞的 goroutine。如果某个 goroutine 还没调用 Wait(比如刚启动、还在做初始化),它不会被“捕获”到这次广播里。
这导致一个常见错觉:「我调了 Broadcast,但新来的协程收不到通知」——其实不是没通知,是它根本没在等。
-
Cond.Broadcast不是“发消息”,而是“拍一下正在打盹的所有人” - 没打盹(没进
Wait)的人,拍不到 - 拍完之后才来打盹的人,得等下一次拍
为什么不能只用 Signal 而要选 Broadcast?
Cond.Signal 只唤醒一个等待者,适用于“单任务分发”场景(比如工作池里唤醒一个空闲 worker);Broadcast 适合“状态变更需全员响应”的情况(比如配置重载、服务关闭信号)。
但要注意:用 Signal 代替 Broadcast 来“省资源”,反而容易出逻辑漏洞——你无法控制谁被唤醒,也无法保证所有关心该事件的 goroutine 都被通知到。
立即学习“go语言免费学习笔记(深入)”;
- 多个 goroutine 等待同一条件时,
Signal可能总唤醒同一个,其余永远卡住 -
Broadcast开销略高,但语义清晰:所有人重新检查条件是否满足 - Go 的
Cond没有“唤醒数量限制”,不担心广播太多导致 panic
必须配 sync.Mutex 才能用 Cond 吗?
是的,而且必须是同一个 sync.Mutex 实例,且在 Wait 前已加锁。
常见错误是把 Cond 和 Mutex 分开管理,或者在 Wait 外部手动解锁——这会导致 Wait 内部 panic,错误信息通常是:sync: inconsistent mutex state。
-
Cond.Wait会自动释放传入的Mutex,并在被唤醒后重新加锁 - 所以调用前必须已持有锁,否则
Wait会直接 panic - 不要在
Wait返回后假设锁还开着——它一定已被重新获取
广播后 goroutine 为什么还要再检查条件?
因为 Cond.Broadcast 不带任何数据,也不保证条件真的成立。它只是说:“嘿,可能有变化了,你自己去看看”。这是防止虚假唤醒(spurious wakeup)和竞态的核心设计。
典型写法是用 for 循环包裹 Wait:
for !conditionMet() {
cond.Wait()
}
如果不检查就直接执行后续逻辑,很可能读到过期状态或引发 panic。
- 即使你 100% 确信广播后条件一定为真,也要检查——这是 Go
Cond的使用契约 - 条件检查本身必须在
Mutex保护下进行(否则读到撕裂值) - 广播方修改条件时,也必须在同一个
Mutex下完成
真正麻烦的从来不是怎么调用 Broadcast,而是谁在什么时候改了条件、谁在什么时候检查、锁的边界包没包住——这些地方一松,问题就藏得深又难复现。










