亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

go語言同步教程之條件變量

2020-04-01 18:55:33
字體:
來源:轉載
供稿:網友

Go的標準庫中有一個類型叫條件變量:sync.Cond。這種類型與互斥鎖和讀寫鎖不同,它不是開箱即用的,它需要與互斥鎖組合使用:

// NewCond returns a new Cond with Locker l.func NewCond(l Locker) *Cond { return &Cond{L: l}}// A Locker represents an object that can be locked and unlocked.type Locker interface { Lock() Unlock()}

通過使用 NewCond 函數可以返回 *sync.Cond 類型的結果, *sync.Cond 我們主要操作其三個方法,分別是:

wait():等待通知

Signal():單播通知

Broadcast():廣播通知

具體的函數說明如下:

// Wait atomically unlocks c.L and suspends execution// of the calling goroutine. After later resuming execution,// Wait locks c.L before returning. Unlike in other systems,// Wait cannot return unless awoken by Broadcast or Signal.//// Because c.L is not locked when Wait first resumes, the caller// typically cannot assume that the condition is true when// Wait returns. Instead, the caller should Wait in a loop://// c.L.Lock()// for !condition() {//  c.Wait()// }// ... make use of condition ...// c.L.Unlock()//func (c *Cond) Wait() { c.checker.check() t := runtime_notifyListAdd(&c.notify) c.L.Unlock() runtime_notifyListWait(&c.notify, t) c.L.Lock()}// Signal wakes one goroutine waiting on c, if there is any.//// It is allowed but not required for the caller to hold c.L// during the call.func (c *Cond) Signal() { c.checker.check() runtime_notifyListNotifyOne(&c.notify)}// Broadcast wakes all goroutines waiting on c.//// It is allowed but not required for the caller to hold c.L// during the call.func (c *Cond) Broadcast() { c.checker.check() runtime_notifyListNotifyAll(&c.notify)}

條件變量sync.Cond本質上是一些正在等待某個條件的線程的同步機制。

sync.Cond 主要實現一個條件變量,假如 goroutine A 執行前需要等待另外的goroutine B 的通知,那邊處于等待的goroutine A 會保存在一個通知列表,也就是說需要某種變量狀態的goroutine A 將會等待/Wait在那里,當某個時刻狀態改變時負責通知的goroutine B 通過對條件變量通知的方式(Broadcast,Signal)來通知處于等待條件變量的goroutine A, 這樣便可首先一種“消息通知”的同步機制。

以go的http處理為例,在Go的源碼中http模塊server部分源碼中所示,當需要處理一個新的連接的時候,若連接conn是實現自*tls.Conn的情況下,會進行相關的客戶端與服務端的“握手”處理Handshake(), 入口代碼如下:

if tlsConn, ok := c.rwc.(*tls.Conn); ok {  if d := c.server.ReadTimeout; d != 0 {   c.rwc.SetReadDeadline(time.Now().Add(d))  }  if d := c.server.WriteTimeout; d != 0 {   c.rwc.SetWriteDeadline(time.Now().Add(d))  }  if err := tlsConn.Handshake(); err != nil {   c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)   return  }  c.tlsState = new(tls.ConnectionState)  *c.tlsState = tlsConn.ConnectionState()  if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {   if fn := c.server.TLSNextProto[proto]; fn != nil {    h := initNPNRequest{tlsConn, serverHandler{c.server}}    fn(c.server, tlsConn, h)   }   return  } }

其中的Handshake函數代碼通過使用條件變量的方式來處理新連接握手調用的同步問題:

func (c *Conn) Handshake() error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() for {  if err := c.handshakeErr; err != nil {   return err  }  if c.handshakeComplete {   return nil  }  if c.handshakeCond == nil {   break  }  c.handshakeCond.Wait() } c.handshakeCond = sync.NewCond(&c.handshakeMutex) c.handshakeMutex.Unlock() c.in.Lock() defer c.in.Unlock() c.handshakeMutex.Lock() if c.handshakeErr != nil || c.handshakeComplete {  panic("handshake should not have been able to complete after handshakeCond was set") } if c.isClient {  c.handshakeErr = c.clientHandshake() } else {  c.handshakeErr = c.serverHandshake() } if c.handshakeErr == nil {  c.handshakes++ } else {  c.flush() } if c.handshakeErr == nil && !c.handshakeComplete {  panic("handshake should have had a result.") } c.handshakeCond.Broadcast() c.handshakeCond = nil return c.hand

我們也可以再通過一個例子熟悉sync.Cond的使用:

我們嘗試實現一個讀寫同步的例子,需求是:我們有數個讀取器和數個寫入器,讀取器必須依賴寫入器對緩存區進行數據寫入后,才可從緩存區中對數據進行讀出。我們思考下,要實現類似的功能,除了使用channel,還能如何做?

寫入器每次完成寫入數據后,它都需要某種通知機制廣播給處于阻塞狀態的讀取器,告訴它們可以對數據進行訪問,這其實跟sync.Cond 的 廣播機制是不是很像? 有了這個廣播機制,我們可以通過sync.Cond來實現這個例子了:

package mainimport ( "bytes" "fmt" "io" "sync" "time")type MyDataBucket struct { br  *bytes.Buffer gmutex *sync.RWMutex rcond *sync.Cond //讀操作需要用到的條件變量}func NewDataBucket() *MyDataBucket { buf := make([]byte, 0) db := &MyDataBucket{  br:  bytes.NewBuffer(buf),  gmutex: new(sync.RWMutex), } db.rcond = sync.NewCond(db.gmutex.RLocker()) return db}func (db *MyDataBucket) Read(i int) { db.gmutex.RLock() defer db.gmutex.RUnlock() var data []byte var d byte var err error for {  //讀取一個字節  if d, err = db.br.ReadByte(); err != nil {   if err == io.EOF {    if string(data) != "" {     fmt.Printf("reader-%d: %s/n", i, data)    }    db.rcond.Wait()    data = data[:0]    continue   }  }  data = append(data, d) }}func (db *MyDataBucket) Put(d []byte) (int, error) { db.gmutex.Lock() defer db.gmutex.Unlock() //寫入一個數據塊 n, err := db.br.Write(d) db.rcond.Broadcast() return n, err}func main() { db := NewDataBucket() go db.Read(1) go db.Read(2) for i := 0; i < 10; i++ {  go func(i int) {   d := fmt.Sprintf("data-%d", i)   db.Put([]byte(d))  }(i)  time.Sleep(100 * time.Millisecond) }}

當使用sync.Cond的時候有兩點移動要注意的:

  • 一定要在調用cond.Wait方法前,鎖定與之關聯的讀寫鎖
  • 一定不要忘記在cond.Wait后,若數據已經處理完畢,在返回前要對與之關聯的讀寫鎖進行解鎖。

如下面 Wait() 的源碼所示,Cond.Wait會自動釋放鎖等待信號的到來,當信號到來后,第一個獲取到信號的Wait將繼續往下執行并從新上鎖

func (c *Cond) Wait() { c.checker.check() t := runtime_notifyListAdd(&c.notify) c.L.Unlock() runtime_notifyListWait(&c.notify, t) c.L.Lock()}

如果不釋放鎖, 其它收到信號的gouroutine將阻塞無法繼續執行。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品无人区太爽高潮在线播放| 日韩精品免费一线在线观看| 欧美大片大片在线播放| 91九色蝌蚪国产| 国产情人节一区| 97久久精品人搡人人玩| 国产脚交av在线一区二区| 中文字幕在线精品| 91视频免费在线| 欧美日韩国产中文字幕| 日韩av网址在线观看| 在线观看日韩av| 中文字幕日韩欧美在线视频| 日本精品免费一区二区三区| 性欧美长视频免费观看不卡| 日韩av三级在线观看| 亚洲精品自拍偷拍| 中文字幕免费精品一区| 国产成人激情小视频| 国产精品三级美女白浆呻吟| 91大神在线播放精品| 日韩av手机在线看| 成人欧美一区二区三区黑人| 亚洲欧洲视频在线| 日韩中文字幕不卡视频| 亚洲人成电影网站色xx| 精品在线欧美视频| 亚洲成人免费网站| 色无极影院亚洲| 欧美国产日本高清在线| 亚洲国产成人精品久久| 欧美亚洲视频一区二区| 久久精品国产综合| 欧美午夜视频在线观看| 国产精品久久久久999| 最近2019年好看中文字幕视频| 亚洲白拍色综合图区| 国产亚洲欧美视频| 国产日韩精品在线| 68精品国产免费久久久久久婷婷| 国产亚洲精品久久久久久牛牛| 国精产品一区一区三区有限在线| 在线成人免费网站| 亚洲深夜福利在线| 国产精品女视频| 成人性生交大片免费看小说| 久久久99久久精品女同性| 日韩美女免费观看| 亚洲美女视频网| 国产精品69精品一区二区三区| 色综合五月天导航| 亚洲天堂第一页| 久久成人在线视频| 性欧美暴力猛交69hd| 久久久精品久久久| 欧美另类老女人| 91精品综合久久久久久五月天| 91精品国产亚洲| 伊人青青综合网站| 日韩免费观看视频| 国产精品视频xxxx| 日韩av高清不卡| 亚洲深夜福利视频| 亚洲а∨天堂久久精品9966| 国产精品美女久久久久av超清| 久久久噜噜噜久久久| 欧美日韩国产综合视频在线观看中文| 性色av一区二区三区红粉影视| 一区二区在线视频播放| 日本精品视频在线播放| 91久久综合亚洲鲁鲁五月天| 尤物tv国产一区| 国产亚洲精品久久久久久777| 日韩欧美有码在线| 91亚洲精品视频| 欧洲中文字幕国产精品| 亚洲欧美日韩中文在线制服| 欧美另类高清videos| 欧美大奶子在线| 91成人免费观看网站| 日韩av片免费在线观看| 欧美日韩亚洲精品一区二区三区| 久久99精品视频一区97| 精品亚洲男同gayvideo网站| 97在线精品国自产拍中文| 日韩高清av一区二区三区| 亚洲一级黄色片| 欧美亚洲成人xxx| 九九久久精品一区| 97视频人免费观看| 日韩亚洲国产中文字幕| 美女扒开尿口让男人操亚洲视频网站| 亚洲美女喷白浆| 91av国产在线| 国产日韩精品在线| 精品偷拍各种wc美女嘘嘘| 精品亚洲男同gayvideo网站| 国产在线拍揄自揄视频不卡99| 国产精品99久久久久久白浆小说| 欧美国产日韩xxxxx| 91精品国产高清久久久久久久久| 亚洲国产99精品国自产| 国产精品久久久久秋霞鲁丝| 欧美www视频在线观看| 亚洲欧洲偷拍精品| 亚洲尤物视频网| 国产精品久久久久久久久久三级| 国产激情久久久久| 大胆人体色综合| 91精品国产乱码久久久久久久久| 久久亚洲精品国产亚洲老地址| 欧美在线视频在线播放完整版免费观看| 欧美日韩中文字幕综合视频| 欧美日韩中文字幕日韩欧美| 精品亚洲va在线va天堂资源站| 中文字幕精品一区二区精品| 日本不卡视频在线播放| 91精品在线国产| 亚洲视频免费一区| 欧美激情三级免费| 国产精品综合网站| 国产69精品99久久久久久宅男| 亚洲欧美中文另类| 一本色道久久88精品综合| 久久91亚洲精品中文字幕奶水| 国产精品高清在线| 黄色精品在线看| 日韩一区二区三区xxxx| 国产丝袜一区二区三区| 日韩欧美成人区| 国产精品女人久久久久久| 久久精品国产v日韩v亚洲| 亚洲免费高清视频| 精品视频在线观看日韩| 亚洲成人黄色网| 久久国产精品免费视频| 国产精品嫩草影院一区二区| 日韩国产欧美精品在线| 久久99久久99精品免观看粉嫩| 国产高清在线不卡| 亚洲成色777777在线观看影院| 久久亚洲精品小早川怜子66| 深夜福利国产精品| 欧美中文在线字幕| 在线免费观看羞羞视频一区二区| 亚洲91精品在线| 亚洲精品按摩视频| 欧美成人全部免费| 亚洲桃花岛网站| 日韩精品高清在线观看| 精品亚洲国产成av人片传媒| 伊人久久精品视频| 国产精品一区二区三区在线播放| 久热精品视频在线观看| 日本伊人精品一区二区三区介绍| 国产a级全部精品| 久久久久国色av免费观看性色| 欧美日韩高清在线观看| 黄色精品在线看| 91精品国产自产91精品| 青青久久av北条麻妃海外网| 色噜噜狠狠狠综合曰曰曰| 日韩欧美国产高清91| 欧美精品福利视频|