阅读更喜欢Golang中的RW互斥锁
我在golang需要一个
read preferring RW互斥锁. golang中是否有满足我需求的包.我试过sync.RWMutex,但似乎是写偏爱锁.我试图区分Go的RWMutex,
package main import ( "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 req second read req done first read after first write granted done first write after second read granted done second read 第二个读者一直等到作家释放锁定. 解决方法
sync.RWMutex实现了write preferred和read首选锁定.这一切都取决于你如何使用它来获得写首选或首选.
将您的维基百科链接伪代码作为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的模式,在读取首选sistuation中的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,它为您提供维基百科示例模式中的整数r,哪些语言(如Go和其他语言)调用信号量: http://www.golangpatterns.info/concurrency/semaphores 对于runtime_Semaquire(),等待的真正含义是在第37行: 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的内存消耗,你可以切换到堆栈上的东西(例如通道,没有互斥锁定)?如何在堆栈上读取数据并保留用于锁定的写入集?有多长时间才能清理堆栈而不必将堆放在堆上?等等 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |