极客时间--golang并发编程实战课--Cond的学习总结
Go标准库的Cond目的是:为等待/通知场景下的并发问题提供支持。Cond通常应用于等待某个条件的一组goroutine,等条件变为true的时候,其中一个goroutine或者所有的goroutine都会被唤醒。
Cond是和某个条件相关,这个条件需要一组goroutine协作共同完成,当条件还没有满足的时候,所有等待这个条件的goroutine都会被阻塞住,只有这一组goroutine通过协作达到了这个条件,等待的goroutine才可能继续进行下去。
等待条件:某个变量达到了某个阈值或者某个时间点,也可以是一组变量分别都达到了某个阈值,还可以是某个对象的状态满足了特定的条件。总结来讲,等待的条件是一种可以用来计算结果是 true 还是 false 的条件。
Cond的基本用法
标准库中的Cond初始化的时候,需要关联一个Locker接口的实例,通常使用Mutex和RMutex
结构:
type Cond struct { noCopy noCopy // L is held while observing or changing the condition L Locker notify notifyList checker copyChecker }
Cond关联的Locker实例可以通过c.L访问,它内部维护着一个先入先出的队列
Signal 方法,允许调用者 Caller 唤醒一个等待此 Cond 的 goroutine。如果此时没有等待的 goroutine,显然无需通知 waiter;如果 Cond 等待队列中有一个或者多个等待的goroutine,则需要从等待队列中移除第一个 goroutine 并把它唤醒。
Broadcast 方法,允许调用者 Caller 唤醒所有等待此 Cond 的 goroutine。如果此时没有等待的 goroutine,显然无需通知 waiter;如果 Cond 等待队列中有一个或者多个等待的goroutine,则清空所有等待的 goroutine,并全部唤醒。syil
Wait 方法,会把调用者 Caller 放入 Cond 的等待队列中并阻塞,直到被 Signal 或者Broadcast 的方法从等待队列中移除并唤醒。调用 Wait 方法时必须要持有 c.L 的锁。
来看一个例子:
package main import ( "log" "math/rand" "sync" "time" ) func main() { c := sync.NewCond(&sync.Mutex{}) var ready int for i := 0; i < 10; i++ { go func(i int) { time.Sleep(time.Duration(rand.Int63n(10)) * time.Second) c.L.Lock() ready++ c.L.Unlock() log.Printf("运动员#%d 已经准备就绪\n", i) c.Broadcast() }(i) } c.L.Lock() for ready != 10 { c.Wait() log.Println("裁判员被唤醒一次") } c.L.Unlock() log.Println("所有运动员准备就绪") }
附课程该章节的总结图: