在 Go 语言中,条件变量(Condition Variable)是一种同步机制,用于协调多个 goroutine 之间的执行,一般与互斥锁(sync.Mutex)配合使用。它允许一个或多个 goroutine 在某个条件不满足时暂停执行(等待),并在其他 goroutine 改变状态并通知条件满足时恢复执行。
Go 语言通过 sync.Cond 类型来实现条件变量。
核心概念
sync.Cond 有三个主要方法:
- Wait(): 使当前 goroutine 释放关联的锁并进入等待状态,直到被 Signal() 或 Broadcast() 唤醒。调用 Wait() 前必须已持有锁。
- Signal(): 唤醒一个正在等待的 goroutine(如果有的话)。如果有多个等待者,唤醒其中一个。
- Broadcast(): 唤醒所有正在等待的 goroutine。
基本用法
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
var cond = sync.NewCond(&mu)
var ready bool
// 等待者 goroutine
go func() {
mu.Lock() // 获取锁
for !ready { // 使用 for 循环检查条件(防止虚假唤醒)
cond.Wait() // 释放锁并等待通知
}
fmt.Println("资源已就绪,开始工作...")
mu.Unlock()
}()
// 通知者 goroutine
go func() {
time.Sleep(2 * time.Second) // 模拟准备资源
mu.Lock()
ready = true
fmt.Println("资源准备完毕,发出通知")
cond.Signal() // 或 cond.Broadcast()
mu.Unlock()
}()
// 等待 goroutine 完成(这里简化处理)
time.Sleep(3 * time.Second)
}
输出:
资源准备完毕,发出通知
资源已就绪,开始工作...
关键要点
- 必须与锁配合使用:sync.Cond 必须关联一个 sync.Locker(一般是 sync.Mutex 或 sync.RWMutex)。Wait() 会自动释放锁,并在唤醒后重新获取锁。
- 使用 for 循环检查条件:永远不要用 if 语句检查条件后调用 Wait()。由于存在虚假唤醒(Spurious Wakeup)的可能性,即 goroutine 在没有收到 Signal 的情况下被唤醒。使用 for !condition 可以确保唤醒后条件的确 满足。
- Signal() vs Broadcast():Signal(): 只唤醒一个等待者。适用于只有一个 goroutine 需要被唤醒的场景(如生产者-消费者模型中的一个消费者)。Broadcast(): 唤醒所有等待者。适用于状态改变可能影响所有等待者的场景。
- 通知时一般需要持有锁:在调用 Signal() 或 Broadcast() 之前,一般需要持有与 Cond 关联的锁,以确保状态的修改是原子的。
总结
sync.Cond 是 Go 中实现条件等待的底层工具,使用时需注意:
- 始终与 sync.Mutex 配合。
- 用 for 循环检查条件。
- 理解 Signal 和 Broadcast 的区别。
- 在大多数需要通信的场景下,channel 是更推荐的高级抽象。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END








![[原创] 【抓包】短链接生成API 腾讯【Url.Cn】新浪【t.Cn】百度【dwz.cn】 - 宋马](https://pic.songma.com/blogimg/20250423/9e69e8d1632441ea9964280ae7510a40.png)









暂无评论内容