目录

Go并发编程实战课笔记—Cond

Go并发编程实战课笔记—Cond

以下大多为鸟窝大佬的Go 并发编程实战课 中摘录的笔记

代码repo

https://img.zhengyua.cn/img/20210107002455.png

Go标准库的Cond

Go 标准库提供 Cond 原语的目的是,为等待 / 通知场景下的并发问题提供支持。

Cond通常应用于等待某个条件的一组goroutine,等条件变为true的时候,其中一个goroutine或者所有的goroutine都会被唤醒执行。

  • 开发实践中使用到Cond场景比较少,且Cond场景一般也能用Channel方式实现,所以更多人会选择使用Channel。

Cond基本用法

标准库中的Cond并发原语初始化的时候需要关联一个Locker接口的实例,一般使用Mutex或者RWMutex。

1
2
3
4
5
type Cond
	func NeWCond(l Locker) *Cond
	func (c *Cond) Broadcast() //允许调用者Caller唤醒所有等待此Cond的goroutine即清空Cond等待队列中所有的goroutine
	func (c *Cond) Signal() //允许调用者Caller按等待队列顺序唤醒一个等待此Cond的goroutine
	func (c *Cond) Wait() //会把调用者Caller放入Cond的等待队列中并阻塞,直到被Signal或者Broadcast方法从等待队列中唤醒。

Go 实现的 sync.Cond 的方法名是 Wait、Signal 和 Broadcast,这是计算机科学中条件变量的通用方法名。

Cond的实现原理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type Cond struct {
	noCopy noCopy
	// 当观察或者修改等待条件的时候需要加锁
	L Locker
	// 等待队列
	notify notifyList
    // 辅助结构,在运行时检查Cond是否被复制使用
	checker copyChecker
}
func NewCond(l Locker) *Cond {
	return &Cond{L: l}
}
func (c *Cond) Wait() {
	c.checker.check()
	// 增加到等待队列中
	t := runtime_notifyListAdd(&c.notify)
	c.L.Unlock()
	// 阻塞休眠直到被唤醒
	runtime_notifyListWait(&c.notify, t)
	c.L.Lock()
}
func (c *Cond) Signal() {
	c.checker.check()
	runtime_notifyListNotifyOne(&c.notify)
}
func (c *Cond) Broadcast() {
	c.checker.check()
	runtime_notifyListNotifyAll(&c.notify
}

使用注意

  • 调用 Wait 的时候没有加锁
  • 只调用了一次Wait,没有检查等待条件是否满足,结果条件没满足,程序就继续执行了。