91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Go Cond

發布時間:2021-10-12 15:05:37 來源:億速云 閱讀:156 作者:iii 欄目:編程語言

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

比如下面這段代碼:

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 來實現

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 實現這個方法還是不容易的。我想這應該是 sync.Cond 唯一有用武之地的地方。

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

  1. cond.Wait本身就是阻塞狀態,為什么 cond.Wait 需要在循環內 ?

  2. sync.Cond 如何觸發不能復制的 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 這樣阻塞的。

調用 goparkunlock 解除當前 goroutine 的 m 的綁定關系,將當前 goroutine 狀態機切換為等待狀態。等待后續 goready 函數時候能夠恢復現場。

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

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

  2. 將已通知 goroutine 的數量加1

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

  4. 被阻塞的 goroutine 可以繼續執行

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

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

  2. 將等待通知的 goroutine 數量和已經通知過的 goroutine 數量設置成相等

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

  4. 所有被阻塞的 goroutine 可以繼續執行

cond.Wait本身就是阻塞狀態,為什么 cond.Wait 需要在循環內 ?

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

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

使用中注意點

1. 不能不加鎖直接調用 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 內部會先調用 c.L.Unlock(),來先釋放鎖。如果調用方不先加鎖的話,會觸發“fatal error: sync: unlock of unlocked mutex”。關于 mutex 的使用方法,推薦閱讀下《這可能是最容易理解的 Go Mutex 源碼剖析》

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

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

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

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

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

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

到此,關于“如何理解Go Cond”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临夏县| 屏边| 余江县| 威宁| 余干县| 潮安县| 盐源县| 鹤壁市| 宜都市| 阿尔山市| 海原县| 苍溪县| 牙克石市| 平山县| 江油市| 乌拉特中旗| 美姑县| 镶黄旗| 老河口市| 砚山县| 和静县| 乌拉特前旗| 怀集县| 丹棱县| 定日县| 沁水县| 临城县| 化隆| 荥经县| 石棉县| 临澧县| 尼勒克县| 栾城县| 遵义县| 天门市| 固安县| 江口县| 惠安县| 库车县| 西峡县| 甘孜|