亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言sync.Cond使用方法詳解

 更新時間:2023年07月18日 11:15:48   作者:碼一行  
Go語言標(biāo)準(zhǔn)庫中還包含條件變量 sync.Cond,它可以讓一組 Goroutine 都在滿足特定條件時被喚醒,每一個sync.Cond結(jié)構(gòu)體在初始化時都需要傳入一個互斥鎖,接下來我們將通過文中例子了解它的使用方法,感興趣的同學(xué)跟著小編一起來看看吧

概述

每一個sync.Cond結(jié)構(gòu)體在初始化時都需要傳入一個互斥鎖,我們可以通過下面的例子了解它的使用方法:

var status int64
func main(){
    c := sync.NewCond(&sync.mutex{})
    for i := 0; i < 10; i++ {
        go listen(c)
    }
    time.Sleep(1 * time.Second)
    go broadcast(c)
    ch := make(chan os.Signal, 1)
    signal.Notify(ch, os.Interrupt)
    <-ch
}
func broadcast(c *sync.Cond) {
    c.L.Lock()
    atomic.StoreInt64(&status, 1)
    c.Broadcast()
    c.L.Unlock()
}
func listen(c *sync.Cond) {
    c.L.Lock()
    for atomic.LoadInt64(&status) != 1 {
        c.Wait()
    }
    fmt.Println("listen")
    c.L.Unlock()
}

運(yùn)行結(jié)果:

listen
...
listen

上述代碼同時運(yùn)行了 11Goroutine,它們分別做了不同事情:

  • 10Goroutine通過sync.Cond.Wait等待特定條件滿足
  • 1Goroutine會調(diào)用sync.Cond.Broadcast喚醒所有陷入等待的Goroutine

調(diào)用sync.Cond.Broadcast方法后,上述代碼會打印出10"listen" 并結(jié)束調(diào)用。

結(jié)構(gòu)體

sync.Cond的結(jié)構(gòu)體中包含以下 4 個字段:

type Cond struct {
    noCopy   noCopy
    L        Locker
    notify   notifyList
    checker  copyChecker
}
  • noCopy —— 用于保證結(jié)構(gòu)體不會在編譯期間復(fù)制
  • L —— 用于保護(hù)內(nèi)部的 notify 字段,Locker 接口類型的變量
  • notify —— 一個 Goroutine 的鏈表,它是實現(xiàn)同步機(jī)制的核心結(jié)構(gòu)
  • copyChecker —— 用于禁止運(yùn)行期間發(fā)生的復(fù)制
type notifyList struct {
    wait   uint32
    notify uint32
    lock   mutex
    head   *sudog
    tail   *sudog
}

sync.notifyList結(jié)構(gòu)體中,headtail分別指向鏈表的頭和尾,waitnotify分別表示當(dāng)前正在等待的和已經(jīng)通知的Goroutine的索引。

接口

sync.Cond對外暴露的sync.Cond.Wait方法會令當(dāng)前Goroutine陷入休眠狀態(tài),它的執(zhí)行過程分成以下兩個步驟:

  • 調(diào)用runtime.notifyListAdd將等待計時器加一并解鎖
  • 調(diào)用runtime.notifyListWait等待其他Goroutine被喚醒并對其加鎖
func (c *Cond) Wait () {
    c.checker.check()
    t := runtime_notifyListAdd(&c.notify)  // runtime.notifyListAdd 的鏈接名
    c.L.Unlock()
    runtime_notifyListWait(&c.notify, t)   //runtime.notifyListWait 的鏈接名
    c.L.Lock()
}
func notifyListAdd(l *notifyList) uint32 {
    return atomic.Xadd(&l.wait, 1) - 1
}

runtime.notifyListWait 會獲取當(dāng)前Goroutine并將它追加到Goroutine通知鏈表的末端:

func notifyListWait(l *notifyList, t uint32) {
    s := acquireSudog()
    s.g = getg()
    s.ticket = t
    if l.tail == nil {
        l.head = s
    } else {
        l.tail.next = s
    }
    l.tail = s
    goparkunlock(&l.lock, waitReasonSyncCondWait, traceEvGoBlockCond, 3)
    releaseSudog(s)
}

除了將當(dāng)前Goroutine追加到鏈表末端外,我們還會調(diào)用runtime.goparkunlock令當(dāng)前Goroutine陷入休眠。該函數(shù)也是在Go語言切換Goroutine時常用的方法,它會直接讓出當(dāng)前處理器的使用權(quán)并等待調(diào)度器喚醒。

sync.Cond.Signalsync.Cond.Broadcast方法就是用來喚醒陷入休眠的Goroutine的,它們的實現(xiàn)有一些細(xì)微差別:

  • sync.Cond.Signal方法會喚醒隊列最前面的Goroutine
  • sync.Cond.Broadcast方法會喚醒隊列中全部Goroutine
func (c *Cond) Signal() {
    c.checker.check()
    runtime_notifyListNotifyOne(&c.notify)
}
func (c *Cond) Broadcast() {
    c.checker.check()
    runtime_notifyListNotifyAll(&c.notify)
}

runtime.notifyListNotifyOne只會從sync.notifyList鏈表中找到滿足sudog.ticket == l.notify條件的Goroutine,并通過runtime.readyWithTime將其喚醒:

func notifyListNotifyOne(l *notifyList) {
    t := l.notify
    atomic.Store(&l.notify, t + 1)
    for p, s := (*sudog)(nil), l.head; s != nil; p, s = s, s.next {
        if s.tiket == t {
            n := s.next
            if p != nil {
                p.next = n
            } else {
                l.head = n
            }
            if n == nil {
                l.tail = p
            }
            s.next = nil
            readyWithTime(s, 4)
            return
        }
    }
}

runtime.notifyListNotifyAll會依次通過runtime.readyWithTime喚醒鏈表中的Goroutine

func notifyListNotifyAll(l *notifyList) {
    s := l.head
    l.head = nil
    l.tail = nil
    atomic.Store(&l.notify, atomic.Load(&l.wait))
    for s != nil {
        next := s.next
        s.next = nil
        readyWithTime(s, 4)
        s = next
    }
}

Goroutine的喚醒順序也是按照加入隊列的先后順序,先加入的會先被喚醒,而后加入的Goroutine可能需要等待調(diào)度器的調(diào)度。

一般情況下,我們會先調(diào)用sync.Cond.Wait陷入休眠等待滿足期望條件,當(dāng)滿足期望條件時,就可以選用sync.Cond.Signal或者sync.Cond.Broadcast喚醒一個或者全部Goroutine。

小結(jié)

sync.Cond不是常用的同步機(jī)制,但是在條件長時間無法滿足時,與使用for {}進(jìn)行忙碌等待相比,sync.Cond能夠讓出處理器的使用權(quán),提高CPU的利用率。

使用時需要注意以下問題:

  • sync.Cond.Wait在調(diào)用之前一定要先獲取互斥鎖,否則會觸發(fā)程序崩潰
  • sync.Cond.Signal喚醒的Goroutine都是隊列最前面、等待最久的Goroutine
  • sync.Cond.Broadcast會按照一定順序廣播通知等待的全部Goroutine

到此這篇關(guān)于Go語言sync.Cond使用方法詳解的文章就介紹到這了,更多相關(guān)Go語言sync.Cond內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解golang延時任務(wù)的實現(xiàn)

    一文詳解golang延時任務(wù)的實現(xiàn)

    這篇文章主要為大家介紹了golang延時任務(wù)的實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 使用Golang編寫一個簡單的命令行工具

    使用Golang編寫一個簡單的命令行工具

    Cobra是一個強(qiáng)大的開源工具,能夠幫助我們快速構(gòu)建出優(yōu)雅且功能豐富的命令行應(yīng)用,本文將利用Cobra編寫一個簡單的命令行工具,感興趣的可以了解下
    2023-12-12
  • Golang中由零值和gob庫特性引起B(yǎng)UG解析

    Golang中由零值和gob庫特性引起B(yǎng)UG解析

    這篇文章主要為大家介紹了Golang中由零值和gob庫特性引起B(yǎng)UG解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • golang+vue打造高效多語言博客系統(tǒng)的完整指南

    golang+vue打造高效多語言博客系統(tǒng)的完整指南

    這篇文章主要為大家詳細(xì)介紹了如何使用golang和vue打造一個高效多語言博客系統(tǒng),本文為大家附上了完整版指南,有需要的小伙伴可以參考一下
    2025-03-03
  • Go語言指針訪問結(jié)構(gòu)體的方法

    Go語言指針訪問結(jié)構(gòu)體的方法

    這篇文章主要介紹了Go語言指針訪問結(jié)構(gòu)體的方法,涉及Go語言指針及結(jié)構(gòu)體的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • GO 使用Webhook 實現(xiàn)github 自動化部署的方法

    GO 使用Webhook 實現(xiàn)github 自動化部署的方法

    這篇文章主要介紹了GO 使用Webhook 實現(xiàn)github 自動化部署的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • Golang中函數(shù)(Function)和方法(Method)的區(qū)別詳解

    Golang中函數(shù)(Function)和方法(Method)的區(qū)別詳解

    在Golang中,大家必然會頻繁使用到函數(shù)(Function)和方法(Method),但是有的同學(xué)可能并沒有注意過函數(shù)和方法的異同點,函數(shù)和方法都是用來執(zhí)行特定任務(wù)的代碼塊,雖然很相似,但也有很大的區(qū)別,所以本文將詳細(xì)講解函數(shù)和方法的定義以及它們的異同點
    2023-07-07
  • Go語言設(shè)置JSON的默認(rèn)值操作

    Go語言設(shè)置JSON的默認(rèn)值操作

    這篇文章主要介紹了Go語言設(shè)置JSON的默認(rèn)值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解

    Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解

    這篇文章主要介紹了Go語言讀取,設(shè)置Cookie及設(shè)置cookie過期方法詳解,需要的朋友可以參考下
    2022-04-04
  • go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    這篇文章主要為大家介紹了go語言reflect.Type?和?reflect.Value?應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09

最新評論