Golang Cond源碼分析

來源:互聯網
上載者:User

cond的主要作用就是擷取鎖之後,wait()方法會等待一個通知,來進行下一步鎖釋放等操作,以此控制鎖合適釋放,釋放頻率,適用於在並發環境下goroutine的等待和通知。

針對Golang 1.9的sync.Cond,與Golang 1.10一樣。 原始碼位置:sync\cond.go。

結構體

type Cond struct {    noCopy noCopy  // noCopy可以嵌入到結構中,在第一次使用後不可複製,使用go vet作為檢測使用    // 根據需求初始化不同的鎖,如*Mutex 和 *RWMutex    L Locker    notify  notifyList  // 通知清單,調用Wait()方法的goroutine會被放入list中,每次喚醒,從這裡取出    checker copyChecker // 複製檢查,檢查cond執行個體是否被複製}

再來看看等待隊列notifyList結構體:

type notifyList struct {    wait   uint32    notify uint32    lock   uintptr    head   unsafe.Pointer    tail   unsafe.Pointer}

函數

NewCond

相當於Cond的建構函式,用於初始化Cond

參數為Locker執行個體初始化,傳參數的時候必須是引用或指標,比如&sync.Mutex{}或new(sync.Mutex),不然會報異常:cannot use lock (type sync.Mutex) as type sync.Locker in argument to sync.NewCond
大家可以想想為什麼一定要是指標呢? 知道的可以給我留言回答。

func NewCond(l Locker) *Cond {    return &Cond{L: l}}

Wait

等待自動解鎖c.L和暫停執行調用goroutine。恢複執行後,等待鎖c.L返回之前。與其他系統不同,等待不能返回,除非通過廣播或訊號喚醒。

因為c。當等待第一次恢複時,L並沒有被鎖定,調用者通常不能假定等待返回時的條件是正確的。相反,調用者應該在迴圈中等待:

func (c *Cond) Wait() {    // 檢查c是否是被複製的,如果是就panic    c.checker.check()    // 將當前goroutine加入等待隊列    t := runtime_notifyListAdd(&c.notify)    // 解鎖    c.L.Unlock()    // 等待隊列中的所有的goroutine執行等待喚醒操作    runtime_notifyListWait(&c.notify, t)    c.L.Lock()}

判斷cond是否被複製。

type copyChecker uintptrfunc (c *copyChecker) check() {    if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&        !atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&        uintptr(*c) != uintptr(unsafe.Pointer(c)) {        panic("sync.Cond is copied")    }}

Signal

喚醒等待隊列中的一個goroutine,一般都是任意喚醒隊列中的一個goroutine,為什麼沒有選擇FIFO的模式呢?這是因為FiFO模式效率不高,雖然支援,但是很少使用到。

func (c *Cond) Signal() {    // 檢查c是否是被複製的,如果是就panic    c.checker.check()    // 通知等待列表中的一個     runtime_notifyListNotifyOne(&c.notify)}

Broadcast

喚醒等待隊列中的所有goroutine。

func (c *Cond) Broadcast() {    // 檢查c是否是被複製的,如果是就panic    c.checker.check()    // 喚醒等待隊列中所有的goroutine    runtime_notifyListNotifyAll(&c.notify)}

執行個體

package mainimport (    "fmt"    "sync"    "time")var locker = new(sync.Mutex)var cond = sync.NewCond(locker)func main() {    for i := 0; i < 40; i++ {        go func(x int) {            cond.L.Lock()         //擷取鎖            defer cond.L.Unlock() //釋放鎖            cond.Wait()           //等待通知,阻塞當前goroutine            fmt.Println(x)            time.Sleep(time.Second * 1)        }(i)    }    time.Sleep(time.Second * 1)    fmt.Println("Signal...")    cond.Signal() // 下發一個通知給已經擷取鎖的goroutine    time.Sleep(time.Second * 1)    cond.Signal() // 3秒之後 下發一個通知給已經擷取鎖的goroutine    time.Sleep(time.Second * 3)    cond.Broadcast() //3秒之後 下發廣播給所有等待的goroutine    fmt.Println("Broadcast...")    time.Sleep(time.Second * 60)}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.