条件变量-sync.Cond

什么是条件变量

与sync.Mutex不同,sync.Cond的作用是在对应的共享数据的状态发生变化时,通知一个或者所以因为共享数据而被阻塞的goroutine。sync.Cond总是与sync.Mutex(或者sync.RWMutex)组合使用。sync.Mutex为共享数据的访问提供互斥锁支持,而sync.Cond可以在共享数据的状态的变化向相关goroutine发出通知。

sync.Cond api

sync.Cond总共有3个方法,一个NewCond创建函数

func NewCond(l Locker) *Cond # 创建NewCond 参数需要是一个`Locker` 一般使用 `sync.Mutex`或者`sync.RWMutex` func (c *Cond) Wait() #阻塞当前goroutine,通过`Signal`或者`Broadcast`唤醒 func (c *Cond) Signal() #唤醒一个被阻塞的goroutine,如果没有的话会忽略。 func (c *Cond) Broadcast() #唤醒一个所有阻塞的goroutine。

我们从sync.Cond提过的api可以看到,它有两种模式,单播和广播。

单播

package main import ( "fmt" "sync" "time" ) func main() { cond := sync.NewCond(new(sync.Mutex)) condition := 0 // Consumer go func() { for { cond.L.Lock() for condition == 0 { cond.Wait() } condition-- fmt.Printf("Consumer: %d\n", condition) cond.Signal() //注意这边会有多次被忽略的情况 cond.L.Unlock() } }() // Producer for { time.Sleep(time.Second) cond.L.Lock() for condition == 3 { cond.Wait() } condition +=3 fmt.Printf("Producer: %d\n", condition) cond.Signal() cond.L.Unlock() } }
$ go run main.go Producer: 3 Consumer: 2 Consumer: 1 Consumer: 0 Producer: 3 Consumer: 2 Consumer: 1 Consumer: 0

多播

package main import ( "fmt" ) var condition = false func main() { m := sync.Mutex{} c := sync.NewCond(&m) go func() { c.L.Lock() for condition == false { fmt.Println("goroutine1 wait") c.Wait() } fmt.Println("goroutine1 exit") c.L.Unlock() }() go func() { c.L.Lock() for condition == false { fmt.Println("goroutine2 wait") c.Wait() } fmt.Println("goroutine2 exit") c.L.Unlock() }() time.Sleep(2e9) c.L.Lock() condition = true c.Broadcast() c.L.Unlock() time.Sleep(2e9) }
$ go run main.go goroutine1 wait goroutine2 wait broadcast goroutine1 exit goroutine2 exit

总结

本小节届时将条件变量的使用,介绍了单播和多播的使用方式。