在RWMutex解锁后两次调用RWMutex RLock时的goroutine块

Ory*_*and 4 concurrency mutex go

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.
Run Code Online (Sandbox Code Playgroud)

如果一个函数读锁定读/写互斥的两倍,而另一个函数写锁,然后直写锁相同的互斥体,原有的功能仍然挂起.

这是为什么?是因为有一个连续顺序,互斥量允许代码执行?

我刚刚通过删除第二mu.RLock()行解决了这样的情况(花了我几个小时精确定位).

Dav*_*e C 9

这是读写锁的几种标准行为之一.什么维基百科称之为"写宁愿RW锁".

文档sync's RWMutex.Lock说:

为确保锁定最终可用,阻止的锁定调用会阻止新读取者获取锁定.

否则,一系列读者在上一次发布之前就已经获得了读锁定,它可能会无限期地挨饿.

这意味着,它始终是不安全的调用RLockRWMutex,同样够程已经读过锁定.(顺便说一下,Lock对于常规互斥锁也是如此,因为Go的互斥锁不支持递归锁定.)

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