<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 簡介 ~~~ var mailbox uint8 var lock sync.RWMutex sendCond := sync.NewCond(&lock) recvCond := sync.NewCond(lock.RLocker()) ~~~ **本身不是鎖,要與鎖結合使用** go標準庫中的sync.Cond類型代表了條件變量. 條件變量要與鎖(互斥鎖,或者讀寫鎖)一起使用.成員變量L代表與條件變量搭配使用的鎖 ~~~ type Cond struct { noCopy noCopy L Locker notify notifyList checker 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() ~~~ **廣播通知,都醒了,驚群**,給正在等待(阻塞)在該條件變量上的所有協程發送通知 # 生產者消費者 ![](https://box.kancloud.cn/e1a172592fa15c6ebd6943eaad94baa6_799x437.png) 代碼注意點是,那里用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 <- num fmt.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 := <-in fmt.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
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看