文章目录
- 前言
- newCond
- Wait
- Signal
- Broadcast
- 和 channel 比较的优势
前言
sync.Cond
基本很少使用,应为大部分都能使用channel
代替sync.Cond
通常是基于sync.Mutex
扩展的- 主要就四个方法
- newCond(l locker) 创建Cond
- Wait() 阻塞等待
- Signal() 唤醒其中一个
- Broadcast() 唤醒全部
newCond
- 需要传入一个 实现
locker
的锁对象,Wait
方法中会使用到
// NewCond returns a new Cond with Locker l.
func NewCond(l Locker) *Cond {
return &Cond{L: l}
}
Wait
checker.check()
进行copy检查runtime_notifyListAdd
加入待通知队列runtime_notifyListWait
阻塞等待唤醒
func (c *Cond) Wait() {
c.checker.check()
t := runtime_notifyListAdd(&c.notify)
c.L.Unlock()
runtime_notifyListWait(&c.notify, t)
c.L.Lock()
}
由于 Wait 开头部分调用了c.L.Unlock(),尾部调用了 c.L.Lock(),所以 wait 要在 c.L.Lock() 和 c.L.Unlock() 之间调用
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
s := sync.NewCond(&sync.Mutex{})
go func() {
s.L.Lock()
fmt.Println("开始进入等待了")
s.Wait()
fmt.Println("需要这样调用哈!")
s.L.Unlock()
wg.Done()
}()
go func() {
time.Sleep(2 * time.Second)
s.Signal()
wg.Done()
fmt.Println("等待我唤醒吧!")
}()
wg.Wait()
fmt.Println("ending")
}
Signal
- 从等待队列中唤醒一个
func (c *Cond) Signal() {
c.checker.check()
runtime_notifyListNotifyOne(&c.notify)
}
Broadcast
- 唤醒全部
- 由于 Wait 中结尾的
c.L.Lock()
全部唤醒还是要参与锁竞争的
func (c *Cond) Broadcast() {
c.checker.check()
runtime_notifyListNotifyAll(&c.notify)
}
和 channel 比较的优势
- 单个唤醒使用 channel 替代 还是挺方便的
- 在全部唤醒下存在优势
- 如果想要全部唤醒,channel需要维护等待的队列
- 由于队列长度不确定,需要使用
slice
slice
并发不安全,那么还需要加锁runtime_notifyListNotifyAll
+runtime_notifyListNotifyOne
的性能优于channel + select + slice FIFO
的实现
k8s中还有很多关于 sync.Cond 的用法,比如
k8s中的 sync.Cond