Golang基础知识—cond
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.Mutexcond = sync.NewCond(&mu)ready bool
)// 等待条件满足的 goroutine
func waiter() {mu.Lock()defer mu.Unlock()for !ready { // 必须用循环检查条件(防止虚假唤醒)cond.Wait()}// 执行条件满足后的操作
}// 修改条件并通知的 goroutine
func setter() {mu.Lock()ready = truemu.Unlock()cond.Signal() // 或 cond.Broadcast()
}
经典示例:生产者-消费者
package mainimport ("fmt""sync""time"
)func main() {var mu sync.Mutexcond := 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
}()