日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

golang中的条件变量

發布時間:2025/6/15 编程问答 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 golang中的条件变量 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

var mailbox uint8 var lock sync.RWMutex sendCond := sync.NewCond(&lock) recvCond := sync.NewCond(lock.RLocker())

本身不是鎖,要與鎖結合使用
go標準庫中的sync.Cond類型代表了條件變量.
條件變量要與鎖(互斥鎖,或者讀寫鎖)一起使用.成員變量L代表與條件變量搭配使用的鎖

type Cond struct {noCopy noCopyL Lockernotify notifyListchecker copyChecker }

對應有3個常用方法: Wait, Signal, Broadcast

func (c *Cond) Wait()
  • 阻塞等待條件變量滿足,等醒
  • 釋放已掌握的互斥鎖相當于cond.L.Unlock().注意:1,2兩步為一個原子操作
  • 當被喚醒的時候,Wait()返回,解除阻塞并重新獲取互斥鎖.相當于cond.L.Lock()

為什么wait要做那3步操作,因為你在等待的時候,把鎖釋放掉啊,讓別人訪問公共空間,然后你被喚醒的時候,你需要拿到鎖,拿到鎖才能對公共空間訪問

func (c *Cond) Signal()

Signal()通知的順序是根據原來加入通知列表(Wait())的先入先出
若沒有Wait(),也不會報錯

單發通知,一次一個,給一個正在等待(阻塞)在該條件變量上的協程發送通知

func (c *Cond) Broadcast()

廣播通知,都醒了,驚群,給正在等待(阻塞)在該條件變量上的所有協程發送通知

生產者消費者


代碼注意點是,那里用for,不用for用if的haul,喚醒后往下執行,如果容量滿的話是會阻塞的,如果是for的話,wait好的話會再次判斷下的,if沒有再次判斷

用if的話,會出現問題而且是偶爾的出現,因為if里面如果喚醒,那么往下如果阻塞,阻塞的話,消費者無法喚醒他了,因為wait已經走過了

//創建全局條件變量 var cond sync.Cond//生產者 func producer(out chan<- int, idx int) {for {//條件變量對應互斥鎖加鎖cond.L.Lock()//注意這邊用for不能用if//循環判斷,如果條件不滿足直接跳過,滿足就等待,因為怕喚醒后有多個生產者一下子讓他充滿//讓他解開的同時,順便判斷下,怕其他生產者已經寫到了3個for len(out) == 3 { //產品區滿,等待消費者cond.Wait() //掛起當前協程,等待條件變量滿足,被消費者喚醒}num := rand.Intn(1000) //產生一個隨機數out <- numfmt.Println("---生產者---產生數據---剩余多少個---", idx, num, len(out))cond.L.Unlock() //生產結束,解鎖互斥鎖cond.Signal() //喚醒阻塞的消費者time.Sleep(time.Second)} }//消費者 func consumer(in <-chan int, idx int) {for {//條件變量對應互斥鎖加鎖(與生產者是同一個)cond.L.Lock()//產品區為空,等待生產者生產for len(in) == 0 {cond.Wait()}//將channel中的數據讀取(消費)num := <-infmt.Println("---消費者---消費數據---公共區剩余多少個---", idx, num, len(in))//消費結束,解鎖互斥鎖cond.L.Unlock()//喚醒阻塞的生產者cond.Signal()//消費者休息一會兒,給其他協程機會time.Sleep(time.Millisecond * 500)} }func main() {rand.Seed(time.Now().UnixNano())//產品區(公共區)使用channel模擬product := make(chan int, 3)//創建互斥鎖和條件變量cond.L = new(sync.Mutex)//生產者for i := 0; i < 5; i++ {go producer(product, i+1)}//消費者for i := 0; i < 3; i++ {go consumer(product, i+1)}for {;} }

注意點

我們在利用條件變量等待通知的時候,需要在它基于的那個互斥鎖保護下進行。而在進行單發通知或廣播通知的時候,卻是恰恰相反的,也就是說,需要在對應的互斥鎖解鎖之后再做這兩種操作。


條件變量并不是被用來保護臨界區和共享資源的,它是用于協調想要訪問共享資源的那些線程的。當共享資源的狀態發生變化時,它可以被用來通知被互斥鎖阻塞的線程。


把調用它的 goroutine(也就是當前的 goroutine)加入到當前條件變量的通知隊列中。

解鎖當前的條件變量基于的那個互斥鎖。

讓當前的 goroutine 處于等待狀態,等到通知到來時再決定是否喚醒它。此時,這個 goroutine 就會阻塞在調用這個Wait方法的那行代碼上。


如果通知到來并且決定喚醒這個 goroutine,那么就在喚醒它之后重新鎖定當前條件變量基于的互斥鎖。自此之后,當前的 goroutine 就會繼續執行后面的代碼了


如果一個 goroutine 因收到通知而被喚醒,但卻發現共享資源的狀態,依然不符合它的要求,那么就應該再次調用條件變量的Wait方法,并繼續等待下次通知的到來。


條件變量的Wait方法總會把當前的 goroutine 添加到通知隊列的隊尾,而它的Signal方法總會從通知隊列的隊首開始,查找可被喚醒的 goroutine。所以,因Signal方法的通知,而被喚醒的 goroutine 一般都是最早等待的那一個。


最后,請注意,條件變量的通知具有即時性。也就是說,如果發送通知的時候沒有 goroutine 為此等待,那么該通知就會被直接丟棄。在這之后才開始等待的 goroutine 只可能被后面的通知喚醒。

適合什么

條件變量適合保護那些可執行兩個對立操作的共享資源。比如,一個既可讀又可寫的共享文件。又比如,既有生產者又有消費者的產品池。

盡量少的鎖爭

相對應的,我們在調用條件變量的 Wait 方法的時候,應該處在其中的鎖的保護之下。因為有同一個鎖保護,所以不可能有多個 goroutine 同時執行到這個 Wait 方法調用,也就不可能存在針對其中鎖的重復解鎖。

對于同一個鎖,多個 goroutine 對它重復鎖定時只會有一個成功,其余的會阻塞;多個 goroutine 對它重復解鎖時也只會有一個成功,但其余的會拋 panic

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的golang中的条件变量的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。