| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package sync |
| |
| // An RWMutex is a reader/writer mutual exclusion lock. |
| // The lock can be held by an arbitrary number of readers |
| // or a single writer. |
| // RWMutexes can be created as part of other |
| // structures; the zero value for a RWMutex is |
| // an unlocked mutex. |
| // |
| // Writers take priority over Readers: no new RLocks |
| // are granted while a blocked Lock call is waiting. |
| type RWMutex struct { |
| w Mutex // held if there are pending readers or writers |
| r Mutex // held if the w is being rd |
| readerCount uint32 // number of pending readers |
| } |
| |
| // RLock locks rw for reading. |
| // If the lock is already locked for writing or there is a writer already waiting |
| // to r the lock, RLock blocks until the writer has released the lock. |
| func (rw *RWMutex) RLock() { |
| // Use rw.r.Lock() to block granting the RLock if a goroutine |
| // is waiting for its Lock. This is the prevent starvation of W in |
| // this situation: |
| // A: rw.RLock() // granted |
| // W: rw.Lock() // waiting for rw.w().Lock() |
| // B: rw.RLock() // granted |
| // C: rw.RLock() // granted |
| // B: rw.RUnlock() |
| // ... (new readers come and go indefinitely, W is starving) |
| rw.r.Lock() |
| if xadd(&rw.readerCount, 1) == 1 { |
| // The first reader locks rw.w, so writers will be blocked |
| // while the readers have the RLock. |
| rw.w.Lock() |
| } |
| rw.r.Unlock() |
| } |
| |
| // RUnlock undoes a single RLock call; |
| // it does not affect other simultaneous readers. |
| // It is a run-time error if rw is not locked for reading |
| // on entry to RUnlock. |
| func (rw *RWMutex) RUnlock() { |
| if xadd(&rw.readerCount, -1) == 0 { |
| // last reader finished, enable writers |
| rw.w.Unlock() |
| } |
| } |
| |
| // Lock locks rw for writing. |
| // If the lock is already locked for reading or writing, |
| // Lock blocks until the lock is available. |
| // To ensure that the lock eventually becomes available, |
| // a blocked Lock call excludes new readers from acquiring |
| // the lock. |
| func (rw *RWMutex) Lock() { |
| rw.r.Lock() |
| rw.w.Lock() |
| rw.r.Unlock() |
| } |
| |
| // Unlock unlocks rw for writing. |
| // It is a run-time error if rw is not locked for writing |
| // on entry to Unlock. |
| // |
| // Like for Mutexes, |
| // a locked RWMutex is not associated with a particular goroutine. |
| // It is allowed for one goroutine to RLock (Lock) an RWMutex and then |
| // arrange for another goroutine to RUnlock (Unlock) it. |
| func (rw *RWMutex) Unlock() { rw.w.Unlock() } |