golang中的條件變數

2021-10-16 22:23:20 字數 2828 閱讀 5541

var mailbox uint8

var lock sync.rwmutex

sendcond := sync.newcond(&lock)

recvcond := sync.newcond(lock.rlocker())

本身不是鎖,要與鎖結合使用go標準庫中的sync.cond型別代表了條件變數.

條件變數要與鎖(互斥鎖,或者讀寫鎖)一起使用.成員變數l代表與條件變數搭配使用的鎖

type cond struct
對應有3個常用方法: wait, signal, broadcast

func (c *cond) wait()
為什麼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

num := rand.intn(1000) //產生乙個隨機數

out

fmt.println("---生產者---產生資料---剩餘多少個---", idx, num, len(out))

cond.l.unlock() //生產結束,解鎖互斥鎖

cond.signal() //喚醒阻塞的消費者

time.sleep(time.second)

}}//消費者

func consumer(in

//將channel中的資料讀取(消費)

num :=

fmt.println("---消費者---消費資料---公共區剩餘多少個---", idx, num, len(in))

//消費結束,解鎖互斥鎖

cond.l.unlock()

//喚醒阻塞的生產者

cond.signal()

//消費者休息一會兒,給其他協程機會

time.sleep(time.millisecond * 500)

}}func main()

//消費者

for i := 0; i < 3; i++

for

}

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

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

把呼叫它的 goroutine(也就是當前的 goroutine)加入到當前條件變數的通知佇列中。

解鎖當前的條件變數基於的那個互斥鎖。

讓當前的 goroutine 處於等待狀態,等到通知到來時再決定是否喚醒它。此時,這個 goroutine 就會阻塞在呼叫這個wait方法的那行**上。

如果通知到來並且決定喚醒這個 goroutine,那麼就在喚醒它之後重新鎖定當前條件變數基於的互斥鎖。自此之後,當前的 goroutine 就會繼續執行後面的**了

如果乙個 goroutine 因收到通知而被喚醒,但卻發現共享資源的狀態,依然不符合它的要求,那麼就應該再次呼叫條件變數的wait方法,並繼續等待下次通知的到來。

條件變數的wait方法總會把當前的 goroutine 新增到通知佇列的隊尾,而它的signal方法總會從通知佇列的隊首開始,查詢可被喚醒的 goroutine。所以,因signal方法的通知,而被喚醒的 goroutine 一般都是最早等待的那乙個。

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

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

盡量少的鎖爭

相對應的,我們在呼叫條件變數的 wait 方法的時候,應該處在其中的鎖的保護之下。因為有同乙個鎖保護,所以不可能有多個 goroutine 同時執行到這個 wait 方法呼叫,也就不可能存在針對其中鎖的重複解鎖。

對於同乙個鎖,多個 goroutine 對它重複鎖定時只會有乙個成功,其餘的會阻塞;多個 goroutine 對它重複解鎖時也只會有乙個成功,但其餘的會拋 panic

Golang中的變數學習小結

golang裡面變數總的來說分四大型別 1.bool,string bool 指布林型別,也就是true,false string 字串型別 2.u int,u int8,u int16,u int32,u int64,uintptr int 和 uint,其中有u和沒有u指的是unsigned指的...

golang條件編譯

golang中沒有類似c語言中條件編譯的寫法,比如在c 中可以使用如下語法做一些條件編譯,結合巨集定義來使用可以實現諸如按需編譯release和debug版本 的需求 ifndef define end但是golang支援兩種條件編譯方式 在源 裡新增標註,通常稱之為編譯標籤 build tag 編...

Golang 條件語句

在go語言中,條件語句主要包括有if switch與select。注意 go語言中沒有三目運算子,不支援?形式的條件判斷。最簡單的if語句的基本語法 if 條件判斷條件判斷如果為真 true 那麼就執行大括號中的語句 如果為假 false 就不執行大括號中的語句,繼續執行if結構後面的 值得注意的是...