亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Golang 中閱讀更喜歡的 RW 互斥鎖

在 Golang 中閱讀更喜歡的 RW 互斥鎖

Go
Cats萌萌 2022-01-04 10:45:37
我需要閱讀更喜歡golang 中的RW互斥鎖。golang中是否有滿足我需求的包。我試過sync.RWMutex,但它似乎是寫優先鎖。這是我試圖區分 Go 的 RWMutex,package mainimport (    "fmt"    "sync"    "time")func main() {y := &resource{x: 10}go func() {    defer fmt.Println("done first read")    y.RLock()    defer y.RUnlock()    go func() {        defer fmt.Println("done first write")        fmt.Println("first write req")        y.Lock()        fmt.Println("after first write granted")        defer y.Unlock()    }()    time.Sleep(time.Second)    go func() {        defer fmt.Println("done second read")        fmt.Println("second read req")        y.RLock()        fmt.Println("after second read granted")        defer y.RUnlock()    }()    time.Sleep(10 * time.Second)}()time.Sleep(time.Minute)}type resource struct {    sync.RWMutex    x int}輸出:first write reqsecond read reqdone first readafter first write granteddone first writeafter second read granteddone second read第二個讀者一直等待直到作者釋放鎖。
查看完整描述

2 回答

?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

sync.RWMutex實現了寫首選和讀首選鎖定。這完全取決于您如何使用它來獲得首選寫入或首選讀取。


以您的 wikipedia 鏈接偽代碼為例,Lock-For-Read(在首選閱讀情況下):


* Input: mutex m, condition variable c, integer r (number of readers waiting), flag w (writer waiting).

* Lock m (blocking).

* While w:

* wait c, m[a]

* Increment r.

* Unlock m.

只要您遵循上述 Lock-For-Reads 模式,就可以在首選讀取的情況下使用 Lock-For-Write 模式:


* Lock m (blocking).

* While (w or r > 0):

* wait c, m

* Set w to true.

* Unlock m.

您可以在RWMutex實現方式中看到這種機制的作用。請記住,Go 框架只是 Go 代碼——查看代碼以了解它是如何實現的:


https://golang.org/src/sync/rwmutex.go?s=879:905#L20


29  // RLock locks rw for reading.

30  func (rw *RWMutex) RLock() {

31      if race.Enabled {

32          _ = rw.w.state

33          race.Disable()

34      }

35      if atomic.AddInt32(&rw.readerCount, 1) < 0 {

36          // A writer is pending, wait for it.

37          runtime_Semacquire(&rw.readerSem)

38      }

39      if race.Enabled {

40          race.Enable()

41          race.Acquire(unsafe.Pointer(&rw.readerSem))

42      }

43  }

需要注意的一個關鍵是rw.readerSem在上面的代碼中,它為您integer r提供了維基百科示例模式,哪些語言(如 Go 和其他語言)稱為信號量:


http://www.golangpatterns.info/concurrency/semaphores


真正的等待在第 37 行,對于runtime_Semaquire():


https://golang.org/src/sync/runtime.go


11  // Semacquire waits until *s > 0 and then atomically decrements it.

12  // It is intended as a simple sleep primitive for use by the synchronization

13  // library and should not be used directly.

14  func runtime_Semacquire(s *uint32)

知道了這一點,并看到了如何RWMutex.RLock()遞增讀取該數字,您可以相應地重構您的代碼。


看看它是如何RWMutex.RUnlock遞減的,但最重要的是如何RWMutex.Lock()強制等待所有活躍的讀者:


71  // Lock locks rw for writing.

72  // If the lock is already locked for reading or writing,

73  // Lock blocks until the lock is available.

74  // To ensure that the lock eventually becomes available,

75  // a blocked Lock call excludes new readers from acquiring

76  // the lock.

77  func (rw *RWMutex) Lock() {

78      if race.Enabled {

79          _ = rw.w.state

80          race.Disable()

81      }

82      // First, resolve competition with other writers.

83      rw.w.Lock()

84      // Announce to readers there is a pending writer.

85      r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders

86      // Wait for active readers.

87      if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {

88          runtime_Semacquire(&rw.writerSem)

89      }

90      if race.Enabled {

91          race.Enable()

92          race.Acquire(unsafe.Pointer(&rw.readerSem))

93          race.Acquire(unsafe.Pointer(&rw.writerSem))

94      }

95  }

這很可能就是您看到第二個讀者在等待的原因。


請記住,信號量不僅在RWMutex您創建的實例之間共享,還在整個運行時共享,以圍繞其他 goroutine 和其他鎖進行調度。因此,為什么在應用程序中嘗試強制模式可能弊大于利。


我的建議是退后一步,考慮一下為什么要在架構中使用讀取優先鎖定。您是否真的處于 CPU 上下文切換會減慢您的高頻應用程序的性能級別?我想說有一個更系統的方法可以被采用,而不是僅僅因為它聽起來很酷并且聽起來它解決了你所有的問題而試圖實現一個“讀取優先鎖定”模式。你的基準數字是多少?輸入數據的大小是多少,以及跨越多少個并發進程?它必須共享嗎?它是否低于 X GB 的內存消耗,您是否可以切換到將內容放在堆棧上(例如通道、沒有互斥鎖)?堆棧上的讀取數據并保留一個寫集用于鎖定呢?GC 清理堆棧需要多長時間,而不必將內容保留在堆上?等等等等。


查看完整回答
反對 回復 2022-01-04
?
九州編程

TA貢獻1785條經驗 獲得超4個贊

似乎可以實現與期望的行為sync.WaitGroup 同步原語,例如


var wg sync.WaitGroup

go func() {

            defer fmt.Println("done second read")

            fmt.Println("second read req")

            y.RLock()   //wait writer

            wg.Add(1)   //report busy

            fmt.Println("after second read granted")

            defer wg.Done() //report done

            defer y.RUnlock()

        }()

//forcing writer to wait all readers

go func() {

            defer fmt.Println("done first write")

            fmt.Println("first write req")

            wg.Wait()  //wait all readers

            y.Lock()

            fmt.Println("after first write granted")

            defer y.Unlock()

        }()

你可以試試https://play.golang.org/p/y831xIrglj


查看完整回答
反對 回復 2022-01-04
  • 2 回答
  • 0 關注
  • 175 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號