cond
通常指 sync.Cond
,它是标准库 sync
包中用于实现 条件变量 的同步原语。条件变量在多 goroutine 协作场景中非常有用,尤其在需要根据特定条件协调多个 goroutine 的执行顺序时。
sync.Cond
的核心作用
条件变量用于 等待某个条件满足 或 通知其他等待者条件已满足。常用于以下场景:
一个或多个 goroutine 需要等待某个条件成立才能继续执行。
某个 goroutine 负责修改条件,并通知其他等待的 goroutine。
sync.Cond
的组成
type Cond struct {
L Locker // 关联的锁(通常是 sync.Mutex 或 sync.RWMutex)
}
主要方法:
Wait()
调用前必须持有锁(
c.L.Lock()
)。释放锁并挂起当前 goroutine,等待被唤醒。
被唤醒后重新获取锁,继续执行。
Signal()
唤醒一个等待的 goroutine(随机选择一个)。
Broadcast()
唤醒所有等待的 goroutine。
基本使用模式
var (
mu sync.Mutex
cond = sync.NewCond(&mu)
ready bool
)
// 等待条件满足的 goroutine
func waiter() {
mu.Lock()
defer mu.Unlock()
for !ready { // 必须用循环检查条件(防止虚假唤醒)
cond.Wait()
}
// 执行条件满足后的操作
}
// 修改条件并通知的 goroutine
func setter() {
mu.Lock()
ready = true
mu.Unlock()
cond.Signal() // 或 cond.Broadcast()
}
经典示例:生产者-消费者
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
queue := make([]int, 0)
// 消费者
go func() {
for {
mu.Lock()
for len(queue) == 0 {
cond.Wait() // 等待队列非空
}
item := queue[0]
queue = queue[1:]
fmt.Println("Consumed:", item)
mu.Unlock()
}
}()
// 生产者
for i := 1; i <= 5; i++ {
time.Sleep(1 * time.Second)
mu.Lock()
queue = append(queue, i)
fmt.Println("Produced:", i)
cond.Signal() // 通知消费者
mu.Unlock()
}
}
关键注意事项
必须用循环检查条件
Wait()
返回后条件可能仍未满足(如虚假唤醒),需循环检查:for conditionNotMet { cond.Wait() }
调用
Wait()
前必须持有锁
否则会导致竞态条件。Signal
vsBroadcast
Signal
:唤醒一个等待者(适用于单消费者)。Broadcast
:唤醒所有等待者(适用于多消费者或条件变化影响所有等待者)。
何时使用 sync.Cond
?
需要 基于复杂条件协调多个 goroutine。
需要 同时唤醒多个等待者(如资源释放时唤醒所有等待的 goroutine)。
对于简单场景,优先考虑使用 channel(Go 的推荐并发模式):
// 用 channel 实现类似功能
ch := make(chan int)
// 生产者
go func() {
ch <- 1
}()
// 消费者
go func() {
item := <-ch
}()