条件变量-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
总结
本小节届时将条件变量的使用,介绍了单播和多播的使用方式。