Created
June 5, 2014 06:57
-
-
Save limingzju/de7e4cc8dc2109b2b75e to your computer and use it in GitHub Desktop.
go read write lock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
import ( | |
"sync/atomic" | |
"unsafe" | |
) | |
// 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. | |
type RWMutex struct { | |
w Mutex // held if there are pending writers | |
writerSem uint32 // semaphore for writers to wait for completing readers | |
readerSem uint32 // semaphore for readers to wait for completing writers | |
readerCount int32 // number of pending readers | |
readerWait int32 // number of departing readers | |
} | |
const rwmutexMaxReaders = 1 << 30 | |
// RLock locks rw for reading. | |
func (rw *RWMutex) RLock() { | |
if raceenabled { | |
_ = rw.w.state | |
raceDisable() | |
} | |
if atomic.AddInt32(&rw.readerCount, 1) < 0 { | |
// A writer is pending, wait for it. | |
runtime_Semacquire(&rw.readerSem) | |
} | |
if raceenabled { | |
raceEnable() | |
raceAcquire(unsafe.Pointer(&rw.readerSem)) | |
} | |
} | |
// 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 raceenabled { | |
_ = rw.w.state | |
raceReleaseMerge(unsafe.Pointer(&rw.writerSem)) | |
raceDisable() | |
} | |
if atomic.AddInt32(&rw.readerCount, -1) < 0 { | |
// A writer is pending. | |
if atomic.AddInt32(&rw.readerWait, -1) == 0 { | |
// The last reader unblocks the writer. | |
runtime_Semrelease(&rw.writerSem) | |
} | |
} | |
if raceenabled { | |
raceEnable() | |
} | |
} | |
// 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() { | |
if raceenabled { | |
_ = rw.w.state | |
raceDisable() | |
} | |
// 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 raceenabled { | |
raceEnable() | |
raceAcquire(unsafe.Pointer(&rw.readerSem)) | |
raceAcquire(unsafe.Pointer(&rw.writerSem)) | |
} | |
} | |
// Unlock unlocks rw for writing. It is a run-time error if rw is | |
// not locked for writing on entry to Unlock. | |
// | |
// As with Mutexes, a locked RWMutex is not associated with a particular | |
// goroutine. One goroutine may RLock (Lock) an RWMutex and then | |
// arrange for another goroutine to RUnlock (Unlock) it. | |
func (rw *RWMutex) Unlock() { | |
if raceenabled { | |
_ = rw.w.state | |
raceRelease(unsafe.Pointer(&rw.readerSem)) | |
raceRelease(unsafe.Pointer(&rw.writerSem)) | |
raceDisable() | |
} | |
// Announce to readers there is no active writer. | |
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) | |
// Unblock blocked readers, if any. | |
for i := 0; i < int(r); i++ { | |
runtime_Semrelease(&rw.readerSem) | |
} | |
// Allow other writers to proceed. | |
rw.w.Unlock() | |
if raceenabled { | |
raceEnable() | |
} | |
} | |
// RLocker returns a Locker interface that implements | |
// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. | |
func (rw *RWMutex) RLocker() Locker { | |
return (*rlocker)(rw) | |
} | |
type rlocker RWMutex | |
func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } | |
func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment