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:
Suppose a reader has acquired the read lock, then rw.readerCount
will be 1.
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.
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
.