真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何理解GoCond

這篇文章主要介紹“如何理解Go Cond”,在日常操作中,相信很多人在如何理解Go Cond問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何理解Go Cond”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

站在用戶的角度思考問題,與客戶深入溝通,找到澄海網(wǎng)站設計與澄海網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設計與互聯(lián)網(wǎng)技術結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站制作、網(wǎng)站設計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名注冊、虛擬主機、企業(yè)郵箱。業(yè)務覆蓋澄海地區(qū)。

比如下面這段代碼:

package mainimport (
 "fmt" "time")func main() {
 done := make(chan int, 1)

 go func() {
  time.Sleep(5 * time.Second)
  done <- 1 }()

 fmt.Println("waiting")
 <-done
 fmt.Println("done")
}

同樣可以使用 sync.Cond 來實現(xiàn)

package mainimport (
 "fmt" "sync" "time")func main() {
 cond := sync.NewCond(&sync.Mutex{})
 var flag bool go func() {
  time.Sleep(time.Second * 5)
  cond.L.Lock()
  flag = true  cond.Signal()
  cond.L.Unlock()
 }()

 fmt.Println("waiting")
 cond.L.Lock()
 for !flag {
  cond.Wait()
 }
 cond.L.Unlock()
 fmt.Println("done")
}

大部分場景下使用 channel 是比 sync.Cond方便的。不過我們要注意到,sync.Cond 提供了 Broadcast 方法,可以通知所有的等待者。想利用 channel 實現(xiàn)這個方法還是不容易的。我想這應該是 sync.Cond 唯一有用武之地的地方。

先列出來一些問題吧,可以帶著這些問題來閱讀本文:

  1. cond.Wait本身就是阻塞狀態(tài),為什么 cond.Wait 需要在循環(huán)內(nèi) ?

  2. sync.Cond 如何觸發(fā)不能復制的 panic ?

  3. 為什么 sync.Cond 不能被復制 ?

  4. cond.Signal 是如何通知一個等待的 goroutine ?

  5. cond.Broadcast 是如何通知等待的 goroutine 的?

源碼剖析

如何理解Go Cond

sync.cond wait

如何理解Go Cond

sync.Cond Signal

如何理解Go Cond

sync.Cond Broadcast

如何理解Go Cond

sync.Cond 排隊動圖

cond.Wait 是阻塞的嗎?是如何阻塞的?

是阻塞的。不過不是 sleep 這樣阻塞的。

調(diào)用 goparkunlock 解除當前 goroutine 的 m 的綁定關系,將當前 goroutine 狀態(tài)機切換為等待狀態(tài)。等待后續(xù) goready 函數(shù)時候能夠恢復現(xiàn)場。

cond.Signal 是如何通知一個等待的 goroutine ?

  1. 判斷是否有沒有被喚醒的 goroutine,如果都已經(jīng)喚醒了,直接就返回了

  2. 將已通知 goroutine 的數(shù)量加1

  3. 從等待喚醒的 goroutine 隊列中,獲取 head 指針指向的 goroutine,將其重新加入調(diào)度

  4. 被阻塞的 goroutine 可以繼續(xù)執(zhí)行

cond.Broadcast 是如何通知等待的 goroutine 的?

  1. 判斷是否有沒有被喚醒的 goroutine,如果都已經(jīng)喚醒了,直接就返回了

  2. 將等待通知的 goroutine 數(shù)量和已經(jīng)通知過的 goroutine 數(shù)量設置成相等

  3. 遍歷等待喚醒的 goroutine 隊列,將所有的等待的 goroutine 都重新加入調(diào)度

  4. 所有被阻塞的 goroutine 可以繼續(xù)執(zhí)行

cond.Wait本身就是阻塞狀態(tài),為什么 cond.Wait 需要在循環(huán)內(nèi) ?

我們能注意到,調(diào)用 cond.Wait 的位置,使用的是 for 的方式來調(diào)用 wait 函數(shù),而不是使用 if 語句。

這是由于 wait 函數(shù)被喚醒時,存在虛假喚醒等情況,導致喚醒后發(fā)現(xiàn),條件依舊不成立。因此需要使用 for 語句來循環(huán)地進行等待,直到條件成立為止。

使用中注意點

1. 不能不加鎖直接調(diào)用 cond.Wait

func (c *Cond) Wait() {
 c.checker.check()
 t := runtime_notifyListAdd(&c.notify)
 c.L.Unlock()
 runtime_notifyListWait(&c.notify, t)
 c.L.Lock()
}

我們看到 Wait 內(nèi)部會先調(diào)用 c.L.Unlock(),來先釋放鎖。如果調(diào)用方不先加鎖的話,會觸發(fā)“fatal error: sync: unlock of unlocked mutex”。關于 mutex 的使用方法,推薦閱讀下《這可能是最容易理解的 Go Mutex 源碼剖析》

2. 為什么不能 sync.Cond 不能復制 ?

sync.Cond 不能被復制的原因,并不是因為 sync.Cond 內(nèi)部嵌套了 Locker。因為 NewCond 時傳入的 Mutex/RWMutex 指針,對于 Mutex 指針復制是沒有問題的。

主要原因是 sync.Cond 內(nèi)部是維護著一個 notifyList。如果這個隊列被復制的話,那么就在并發(fā)場景下導致不同 goroutine 之間操作的 notifyList.wait、notifyList.notify 并不是同一個,這會導致出現(xiàn)有些 goroutine 會一直堵塞。

這里留下一個問題,sync.Cond 內(nèi)部是有一段代碼 check sync.Cond 是不能被復制的,下面這段代碼能觸發(fā)這個 panic 嗎?

package mainimport (
 "fmt" "sync")func main() {
 cond1 := sync.NewCond(new(sync.Mutex))
 cond := *cond1
 fmt.Println(cond)
}

有興趣的可以動手嘗試下,以及嘗試下如何才能觸發(fā)這個panic "sync.Cond is copied” 。

到此,關于“如何理解Go Cond”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
當前標題:如何理解GoCond
分享網(wǎng)址:http://weahome.cn/article/ppcjid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部