Go語言—sync.Cond原始碼分析

w1015357065發表於2019-12-30


點選這裡,檢視 剩餘 signal 與 broadcast 的解析以及實際舉例    


Cond 的主要作用就是獲取鎖之後,wait() 方法會等待一個通知,來進行下一步鎖釋放等操作,以此控制鎖合適釋放,釋放頻率,適用於在併發環境下 goroutine 的等待和通知。

針對 Golang 1.9 的 sync.Cond,與 Golang 1.10 一樣。 原始碼位置:sync\cond.go。

結構體

type Cond struct {
noCopy noCopy // noCopy 可以嵌入到結構中,在第一次使用後不可複製,使用 go vet 作為檢測使用

// 根據需求初始化不同的鎖,如*Mutex 和 *RWMutex
L Locker

notify notifyList // 通知列表,呼叫 Wait() 方法的 goroutine 會被放入 list 中,每次喚醒,從這裡取出
checker copyChecker // 複製檢查,檢查 cond 例項是否被複制
}


再來看看等待佇列 notifyList 結構體:


type notifyList struct {
wait uint32
notify uint32
lock uintptr
head unsafe.Pointer
tail unsafe.Pointer
}

函式

NewCond

相當於 Cond 的建構函式,用於初始化 Cond。

引數為 Locker 例項初始化,傳引數的時候必須是引用或指標,比如&sync.Mutex{}或 new(sync.Mutex),不然會報異常:cannot use lock (type sync.Mutex) as type sync.Locker in argument to sync.NewCond。

大家可以想想為什麼一定要是指標呢? 因為如果傳入 Locker 例項,在呼叫 c.L.Lock() 和 c.L.Unlock() 的時候,會頻繁發生鎖的複製,會導致鎖的失效,甚至導致死鎖。


func NewCond(l Locker) *Cond {
return &Cond{L: l}
}

Wait
等待自動解鎖 c.L 和暫停執行呼叫 goroutine。恢復執行後,等待鎖 c.L 返回之前。與其他系統不同,等待不能返回,除非通過廣播或訊號喚醒。

因為 c。當等待第一次恢復時,L 並沒有被鎖定,呼叫者通常不能假定等待返回時的條件是正確的。相反,呼叫者應該在迴圈中等待:


func (c *Cond) Wait() {
// 檢查 c 是否是被複制的,如果是就 panic
c.checker.check()
// 將當前 goroutine 加入等待佇列
t := runtime_notifyListAdd(&c.notify)
// 解鎖
c.L.Unlock()
// 等待佇列中的所有的 goroutine 執行等待喚醒操作
runtime_notifyListWait(&c.notify, t)
c.L.Lock()
}

關鍵字:go 語言    sync.Cond    原始碼解讀    


更多原創文章乾貨分享,請關注公眾號
  • Go語言—sync.Cond原始碼分析
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章