Goroutine blocks when calling RWMutex RLock twice after unlocking RWMutex

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.

      

If a read function locks a read / write mutex twice, while another write locks and then write- un locks the same mutex, the original function is still hanging.

Why? Is it because there is a sequential order in which mutexes allow code to be executed?

I just solved a scenario like this (which took me hours to figure out) by removing the second line mu.RLock()

.

+3


source to share


1 answer


This is one of several standard actions for blocking read and write. What Wikipedia calls "Write-prefering RW locks" .

The documentation for sync's

RWMutex.Lock

says:

To ensure that the lock is eventually available, the blocked call to the lock prevents new readers from acquiring the lock.



Otherwise, a series of readers who each acquired a read lock before it was released could starve to death indefinitely.

This means that it is always unsafe to call RLock

on RWMutex

that the same goroutine is already blocked. (By the way, this also applies to Lock

regular mutexes, since Go mutexes do not support recursive locking.)

The reason this is unsafe is that if goroutine ever blocks acquiring a second read lock (due to a locked author), it will never release the first read lock. This will cause each subsequent call to lock the mutex to block forever, blocking part or all of the program. Go will only detect deadlock if all goroutines are blocked.

+7


source







All Articles