编程语言
813
定义
Cond是sync包里的一个结构体类型,表示条件变量。我们知道sync.WaitGroup可以用于等待所有goroutine都执行完成,sync.Cond可以用于控制goroutine什么时候开始执行。
Cond结构体类型定义如下:
type Cond struct { L Locker // some other fields }
Cond结构体类型以下几个方法与其紧密相关:
-
NewCond函数,用于创建条件变量,条件变量的成员
L
是NewCond函数的参数l
func NewCond(l Locker) *Cond
-
Broadcast,发出广播,唤醒所有等待条件变量c的goroutine开始执行。注意:在调用Broadcast方法之前,要确保目标goroutine处于Wait阻塞状态,不然会出现死锁问题。
func (c *Cond) Broadcast()
-
Signal,发出信号,唤醒某一个等待条件变量c的goroutine开始执行。注意:在调用Signal方法之前,要确保目标goroutine处于Wait阻塞状态,不然会出现死锁问题。
func (c *Cond) Signal()
-
Wait,这个方法会解锁c.L以及阻塞当前goroutine往下执行,解锁和阻塞组合在一起构成原子操作。Wait被Broadcast或者Signal唤醒时,会先对c.L加锁,然后Wait才return返回。
func (c *Cond) Wait()
每个Cond变量都有一个Locker类型的成员L,L通常是*Mutex或者*RWMutex类型,调用Wait方法时要对L加锁。
不要对Cond变量使用值传递进行函数调用。
示例
下面这个示例,先开启了10个goroutine,这10个goroutine都进入Wait阻塞状态,等待被唤醒。
package main import ( "fmt" "sync" "time" ) func main() { var wg sync.WaitGroup /**/ var mutex sync.Mutex cond := sync.NewCond(&mutex) size := 10 wg.Add(size+1) for i:=0; i<size; i++ { i := i go func() { defer wg.Done() /*调用Wait方法时,要对L加锁*/ cond.L.Lock() fmt.Printf("%d ready\n", i) /*Wait实际上是会先解锁cond.L,再阻塞当前goroutine 这样其它goroutine调用上面的cond.L.Lock()才能加锁成功,才能进一步执行到Wait方法, 等待被Broadcast或者signal唤醒。 Wait被Broadcast或者Signal唤醒的时候,会再次对cond.L加锁,加锁后Wait才会return */ cond.Wait() fmt.Printf("%d done\n", i) cond.L.Unlock() }() } /*这里sleep 2秒,确保目标goroutine都处于Wait阻塞状态 如果调用Broadcast之前,目标goroutine不是处于Wait状态,会死锁 */ time.Sleep(2*time.Second) go func() { defer wg.Done() cond.Broadcast() }() wg.Wait() }