Golang中RWMutex.Lock()的实现

in src/sync/rwmutex.go file, we can see the definition of "Lock" as follows:

func (rw *RWMutex) Lock() {
    if race.Enabled {
        _ = rw.w.state
        race.Disable()
    }
    // First, resolve competition with other writers.
    rw.w.Lock()
    // Announce to readers there is a pending writer.
    r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    // Wait for active readers.
    if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
        runtime_Semacquire(&rw.writerSem)
    }
    if race.Enabled {
        race.Enable()
        race.Acquire(unsafe.Pointer(&rw.readerSem))
        race.Acquire(unsafe.Pointer(&rw.writerSem))
    }
}

So I really wonder what

atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders

this sentence means. And as it says, how to announce to readers? How to understand it?

Do you like magic? This is that ;o) No .. I'm just kidding.

We could start with

atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders)

This atomically substract rwmutexMaxReaders from rw.readerCount. New value is stored into rw.readerCount and also returned by function. And when you will add rwmutexMaxReaders you just compute old value rw.readerCount before AddInt32.

On a RWMutex a writer calling Lock prevents more readers from acquiring the RLock. This is done to prevent starvation of writers.

Suppose the following scenario:

  1. Suppose a reader has acquired the read lock, then rw.readerCount will be 1.

  2. A writer then tries to acquire the write lock. After acquiring the write lock (line 93) it now has to signal all the readers that a writer is waiting (so they can't continue) and wait for all the readers to finish. The signal is set by setting rw.readerCount to a negative value (atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders)). The value of rw.readerCount is now 1-rwmutexMaxReaders. Note that r is not 0, so the writer knows there is a reader still reading.

  3. A new Reader now wants to acquire the read lock, it adds 1 to rw.readerCount (line 48) and checks if it is negative. If it is negative a writer has set it as such, and we should wait for the writer to finish before continuing.

The signaling happens around the sign of rw.readerCount.