var mu sync.RWMutex

go func() {
    mu.RLock()
    defer mu.RUnlock()

    mu.RLock()  // In my real scenario this second lock happened in a nested function.
    defer mu.RUnlock()

    // More code.
}()

mu.Lock()
mu.Unlock()  // The goroutine above still hangs.

如果一个函数读锁定一个读/写互斥锁两次,而另一个函数写锁然后写- un 锁定同一个互斥锁,原始函数仍然挂起。

这是为什么?是不是因为互斥体允许代码执行有一个串行顺序?

我刚刚通过删除第二个 mu.RLock() 行解决了这样的场景(我花了几个小时才确定)。

最佳答案

这是读写锁的几种标准行为之一。什么 Wikipedia calls "Write-preferring RW locks"
sync's RWMutex.Lock 的文档说:



否则,在前一个释放之前,每个读取锁都获得了读取锁的一系列读取器可能会无限期地使写入饥饿。

这意味着在同一个 goroutine 已经读取锁定的 RLock 上调用 RWMutex 总是不安全的。 (顺便说一下,常规互斥锁上的 Lock 也是如此,因为 Go 的互斥锁不支持递归锁定。)

它不安全的原因是,如果 goroutine 阻止获取第二个读锁(由于被阻塞的写入器),它将永远不会释放第一个读锁。这将导致对互斥锁的每个 future 锁调用永远阻塞,导致程序的一部分或全部死锁。如果所有 goroutine 都被阻塞,Go 只会检测到死锁。

关于concurrency - goroutine 在 RWMutex Unlock 后调用 RWMutex RLock 两次时阻塞,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30547916/

10-10 23:56