src/pkg/sync/rwmutex.go - The Go Programming Language

Golang

Source file src/pkg/sync/rwmutex.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package sync
     6	
     7	import "sync/atomic"
     8	
     9	// An RWMutex is a reader/writer mutual exclusion lock.
    10	// The lock can be held by an arbitrary number of readers
    11	// or a single writer.
    12	// RWMutexes can be created as part of other
    13	// structures; the zero value for a RWMutex is
    14	// an unlocked mutex.
    15	type RWMutex struct {
    16		w           Mutex  // held if there are pending writers
    17		writerSem   uint32 // semaphore for writers to wait for completing readers
    18		readerSem   uint32 // semaphore for readers to wait for completing writers
    19		readerCount int32  // number of pending readers
    20		readerWait  int32  // number of departing readers
    21	}
    22	
    23	const rwmutexMaxReaders = 1 << 30
    24	
    25	// RLock locks rw for reading.
    26	func (rw *RWMutex) RLock() {
    27		if atomic.AddInt32(&rw.readerCount, 1) < 0 {
    28			// A writer is pending, wait for it.
    29			runtime_Semacquire(&rw.readerSem)
    30		}
    31	}
    32	
    33	// RUnlock undoes a single RLock call;
    34	// it does not affect other simultaneous readers.
    35	// It is a run-time error if rw is not locked for reading
    36	// on entry to RUnlock.
    37	func (rw *RWMutex) RUnlock() {
    38		if atomic.AddInt32(&rw.readerCount, -1) < 0 {
    39			// A writer is pending.
    40			if atomic.AddInt32(&rw.readerWait, -1) == 0 {
    41				// The last reader unblocks the writer.
    42				runtime_Semrelease(&rw.writerSem)
    43			}
    44		}
    45	}
    46	
    47	// Lock locks rw for writing.
    48	// If the lock is already locked for reading or writing,
    49	// Lock blocks until the lock is available.
    50	// To ensure that the lock eventually becomes available,
    51	// a blocked Lock call excludes new readers from acquiring
    52	// the lock.
    53	func (rw *RWMutex) Lock() {
    54		// First, resolve competition with other writers.
    55		rw.w.Lock()
    56		// Announce to readers there is a pending writer.
    57		r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    58		// Wait for active readers.
    59		if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
    60			runtime_Semacquire(&rw.writerSem)
    61		}
    62	}
    63	
    64	// Unlock unlocks rw for writing.  It is a run-time error if rw is
    65	// not locked for writing on entry to Unlock.
    66	//
    67	// As with Mutexes, a locked RWMutex is not associated with a particular
    68	// goroutine.  One goroutine may RLock (Lock) an RWMutex and then
    69	// arrange for another goroutine to RUnlock (Unlock) it.
    70	func (rw *RWMutex) Unlock() {
    71		// Announce to readers there is no active writer.
    72		r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
    73		// Unblock blocked readers, if any.
    74		for i := 0; i < int(r); i++ {
    75			runtime_Semrelease(&rw.readerSem)
    76		}
    77		// Allow other writers to proceed.
    78		rw.w.Unlock()
    79	}
    80	
    81	// RLocker returns a Locker interface that implements
    82	// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
    83	func (rw *RWMutex) RLocker() Locker {
    84		return (*rlocker)(rw)
    85	}
    86	
    87	type rlocker RWMutex
    88	
    89	func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
    90	func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }