如果写入在设计上从不相互竞争,那么使用sync.RWMutex的读锁进行写入并使用其写入锁进行读

来自 Go 文档:

RWMutex 是读取器/写入器互斥锁。该锁可以由任意数量的读取器或单个写入器持有。

这个介绍性句子后面从来没有定义读者和作者可以做什么和不可以做什么。因此,我想知道这个定义的某种延伸是否可能。

假设我们有一组许多 goroutine;我们就这么称呼它吧S。中的每个 goroutineS都有自己的资源,可以频繁地读取和写入这些资源。假设我有一个额外的 goroutine R,它通常想要抓取S. 让我们探索两个更明显的解决方案,看看我要去哪里。

  1. 我们可以使用单个互斥体。然而, 中的 goroutineS会不必要地争夺锁,因为S无论如何,每个 goroutine 都只能访问自己的资源。

  2. 为 中的每个 goroutine 使用一个互斥体S。这消除了不必要的竞争,甚至提供了R决定是否需要立即锁定所有互斥锁或仅在某个时间点至少锁定每个互斥锁一次的选项。然而需要一些额外的工作。

所以我的第三个想法是:让 goroutine 在想要读或写时S获取 a 的读锁(即广义的包含锁),并在想要读取时获取该互斥锁的写锁(即广义的独占锁))。换句话说: sync.RWMutexR

sync.RWMutex如果写入在设计上从不相互竞争,那么使用 的读锁进行写入并使用其写入锁进行读取是否安全?


有只小跳蛙
浏览 107回答 2
2回答

呼啦一阵风

你的问题的答案是肯定的,正如沃尔克所说。我会给你一个更惯用的 Go 解决方案:every resources of goroutines in S take a sync.RWMutexthe goroutines in S read after sync.RWMutex.Rlock()the goroutines in S write after sync.RWMutex.Lock()extra goroutine R read after sync.RWMutex.Rlock()我认为你只是进入了错误的区域,这应该是一个简单的问题。:)如果我误解了你,请告诉我。

慕斯王

由于所有的困惑而回答自己。sync.RWMutex是的,如果写入不会相互竞争,则使用 的读锁进行写入并使用其写入锁进行读取是安全的。例子:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; m := &sync.RWMutex{}&nbsp; &nbsp; wg := &sync.WaitGroup{}&nbsp; &nbsp; maxWriters := 5&nbsp; &nbsp; wg.Add(maxWriters+1)&nbsp; &nbsp; allData := make([]uint64, maxWriters)&nbsp; &nbsp; go showAccumulatedData(m, wg, allData)&nbsp; &nbsp; for i := 0; i < maxWriters; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go writeData(m, wg, &allData[i])&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; fmt.Println(accumulateData(m, allData))}func writeData(m *sync.RWMutex, wg *sync.WaitGroup, d *uint64) {&nbsp; &nbsp; for i := 0; i < 1000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; m.RLock()&nbsp; &nbsp; &nbsp; &nbsp; *d++ // Write during read-lock.&nbsp; &nbsp; &nbsp; &nbsp; m.RUnlock()&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(time.Millisecond)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()}func showAccumulatedData(m *sync.RWMutex, wg *sync.WaitGroup, allData []uint64) {&nbsp; &nbsp; for i := 0; i < 15; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(accumulateData(m, allData))&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(time.Millisecond*50)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()}func accumulateData(m *sync.RWMutex, allData []uint64) uint64 {&nbsp; &nbsp; var accumulator uint64&nbsp; &nbsp; m.Lock()&nbsp; &nbsp; for _, v := range allData {&nbsp; &nbsp; &nbsp; &nbsp; accumulator += v // Read during write-lock.&nbsp; &nbsp; }&nbsp; &nbsp; m.Unlock()&nbsp; &nbsp; return&nbsp; accumulator}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go