Go 并發(fā)實(shí)戰(zhàn) -- sync Cond

前言

go中的sync.Cond也就是condition兰迫,是一個(gè)條件同步變量辈双,與Java中Object的wait聚请、notify蹄衷、notifyAll方法或者Condition類的作用比較類似忧额,如果有這方面的基礎(chǔ)學(xué)習(xí)起來(lái)會(huì)非常簡(jiǎn)單。其實(shí)Java中的JUC包實(shí)現(xiàn)的可以是最豐富和易用的了愧口,熟知JUC的話睦番,學(xué)習(xí)其他語(yǔ)言的并發(fā)特性及工具的話會(huì)非常簡(jiǎn)單。

語(yǔ)法基礎(chǔ)

sync.Cond同其他并發(fā)條件變量一樣耍属,提供了阻塞和喚醒函數(shù):
Wait() 阻塞操作
Signal() 喚醒一個(gè)協(xié)程
Broadcast() 喚醒所有協(xié)程
不同的Cond需要我們制定一把鎖托嚣,通常是Mutex、RWMytex厚骗,當(dāng)然也可以是你自己實(shí)現(xiàn)的鎖示启。
下面來(lái)看一下sync.Cond的使用:

func main() {
    lock := &sync.Mutex{}
    cond := sync.NewCond(lock)
    for i:=0; i<10; i++ {
        runGorotine(cond, i)
    }
    time.Sleep(1*time.Millisecond)
    fmt.Println("----------------------------: signal 喚醒單個(gè)")
    cond.Signal()
    time.Sleep(1*time.Millisecond)
    fmt.Println("----------------------------: broadcast 喚醒全部")
    cond.Broadcast()
    time.Sleep(2*time.Second)
}

func runGorotine(cond *sync.Cond, i int) {
    go func(cond *sync.Cond, i int) {
        cond.L.Lock()
        for condition() {
            fmt.Println("-goroutine-" + strconv.Itoa(i) + " 命中wait")
            cond.Wait()
        }
        fmt.Println("-goroutine-" + strconv.Itoa(i) + " 命中條件")
        cond.L.Unlock()
    }(cond, i)
}

func condition() bool {
    rand.Intn(50)
    if rand.Intn(50) > 20 {
        fmt.Print(true)
        return true
    }
    fmt.Print(false)
    return false
}

輸出:


image.png

ps:go 協(xié)程之后啟動(dòng)后并不是立即執(zhí)行的,需要有一定的分配過(guò)程及等待的時(shí)間,所以說(shuō)sleep一小段時(shí)間领舰,否則喚醒通知在wait之前發(fā)生就沒(méi)有意義了夫嗓。
上述就是Cond的最簡(jiǎn)單的使用,生產(chǎn)環(huán)境比這個(gè)demo要復(fù)雜一些冲秽,但是大致也就這樣了舍咖。

實(shí)現(xiàn)原理

Cond的實(shí)現(xiàn)非常簡(jiǎn)單,鎖操作依賴的是我們創(chuàng)建的lock锉桑。然后依賴于runtime阻塞和喚醒go協(xié)程的函數(shù)排霉。

type Cond struct {
// 這個(gè)已經(jīng)不是第一次見(jiàn)了,第一次使用后就不能copy了
    noCopy noCopy
    L Locker // 創(chuàng)建cond是傳入的鎖
    notify  notifyList // 調(diào)用runtime阻塞和喚醒的函數(shù)民轴,內(nèi)部維護(hù)了一個(gè)阻塞鏈表
    checker copyChecker // 保留指向自身的指針以檢測(cè)對(duì)象復(fù)制攻柠。
}
// 構(gòu)造函數(shù)
func NewCond(l Locker) *Cond {
    return &Cond{L: l}
}

wait函數(shù)的鎖邏輯有點(diǎn)奇怪球订,其實(shí)主要是為了把外面條件判斷和添加阻塞隊(duì)列變?yōu)橐粋€(gè)原子操作,這種鎖的使用方式其實(shí)不太建議瑰钮,比較容易出問(wèn)題冒滩。

func (c *Cond) Wait() {
    c.checker.check()
    t := runtime_notifyListAdd(&c.notify) // 添加阻塞列表
    c.L.Unlock() // 函數(shù)調(diào)用前已經(jīng)加鎖了,在添加阻塞隊(duì)列后就可以撤銷鎖了
    runtime_notifyListWait(&c.notify, t) // 進(jìn)行阻塞
    c.L.Lock() // 外層還有個(gè)解鎖操作浪谴,加把鎖
}

下面是喚醒操作:

func (c *Cond) Signal() {
    c.checker.check()
    runtime_notifyListNotifyOne(&c.notify) 
    // 喚醒一個(gè)
}

func (c *Cond) Broadcast() {
    c.checker.check()
    runtime_notifyListNotifyAll(&c.notify)
    // 喚醒多個(gè)
}

關(guān)于Cond的使用及源碼實(shí)現(xiàn)暫時(shí)介紹這么多旦部。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市较店,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌容燕,老刑警劉巖梁呈,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蘸秘,居然都是意外死亡官卡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門醋虏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)寻咒,“玉大人,你說(shuō)我怎么就攤上這事颈嚼∶兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵阻课,是天一觀的道長(zhǎng)叫挟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)限煞,這世上最難降的妖魔是什么抹恳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮署驻,結(jié)果婚禮上奋献,老公的妹妹穿的比我還像新娘。我一直安慰自己旺上,他們只是感情好瓶蚂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著抚官,像睡著了一般扬跋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凌节,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天钦听,我揣著相機(jī)與錄音洒试,去河邊找鬼。 笑死朴上,一個(gè)胖子當(dāng)著我的面吹牛垒棋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播痪宰,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼叼架,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衣撬?” 一聲冷哼從身側(cè)響起乖订,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎具练,沒(méi)想到半個(gè)月后乍构,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扛点,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年哥遮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陵究。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡眠饮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铜邮,到底是詐尸還是另有隱情仪召,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布松蒜,位于F島的核電站返咱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牍鞠。R本人自食惡果不足惜咖摹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望难述。 院中可真熱鬧萤晴,春花似錦、人聲如沸胁后。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)攀芯。三九已至屯断,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背殖演。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工氧秘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趴久。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓丸相,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親彼棍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子灭忠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容