rwmutex.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. package sync
  5. import (
  6. "sync/atomic"
  7. "unsafe"
  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. const rwmutexMaxReaders = 1 << 30
  23. // RLock locks rw for reading.
  24. func (rw *RWMutex) RLock() {
  25. if raceenabled {
  26. _ = rw.w.state
  27. raceDisable()
  28. }
  29. if atomic.AddInt32(&rw.readerCount, 1) < 0 {
  30. // A writer is pending, wait for it.
  31. runtime_Semacquire(&rw.readerSem)
  32. }
  33. if raceenabled {
  34. raceEnable()
  35. raceAcquire(unsafe.Pointer(&rw.readerSem))
  36. }
  37. }
  38. // RUnlock undoes a single RLock call;
  39. // it does not affect other simultaneous readers.
  40. // It is a run-time error if rw is not locked for reading
  41. // on entry to RUnlock.
  42. func (rw *RWMutex) RUnlock() {
  43. if raceenabled {
  44. _ = rw.w.state
  45. raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
  46. raceDisable()
  47. }
  48. if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
  49. if r+1 == 0 || r+1 == -rwmutexMaxReaders {
  50. raceEnable()
  51. panic("sync: RUnlock of unlocked RWMutex")
  52. }
  53. // A writer is pending.
  54. if atomic.AddInt32(&rw.readerWait, -1) == 0 {
  55. // The last reader unblocks the writer.
  56. runtime_Semrelease(&rw.writerSem)
  57. }
  58. }
  59. if raceenabled {
  60. raceEnable()
  61. }
  62. }
  63. // Lock locks rw for writing.
  64. // If the lock is already locked for reading or writing,
  65. // Lock blocks until the lock is available.
  66. // To ensure that the lock eventually becomes available,
  67. // a blocked Lock call excludes new readers from acquiring
  68. // the lock.
  69. func (rw *RWMutex) Lock() {
  70. if raceenabled {
  71. _ = rw.w.state
  72. raceDisable()
  73. }
  74. // First, resolve competition with other writers.
  75. rw.w.Lock()
  76. // Announce to readers there is a pending writer.
  77. r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
  78. // Wait for active readers.
  79. if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
  80. runtime_Semacquire(&rw.writerSem)
  81. }
  82. if raceenabled {
  83. raceEnable()
  84. raceAcquire(unsafe.Pointer(&rw.readerSem))
  85. raceAcquire(unsafe.Pointer(&rw.writerSem))
  86. }
  87. }
  88. // Unlock unlocks rw for writing. It is a run-time error if rw is
  89. // not locked for writing on entry to Unlock.
  90. //
  91. // As with Mutexes, a locked RWMutex is not associated with a particular
  92. // goroutine. One goroutine may RLock (Lock) an RWMutex and then
  93. // arrange for another goroutine to RUnlock (Unlock) it.
  94. func (rw *RWMutex) Unlock() {
  95. if raceenabled {
  96. _ = rw.w.state
  97. raceRelease(unsafe.Pointer(&rw.readerSem))
  98. raceRelease(unsafe.Pointer(&rw.writerSem))
  99. raceDisable()
  100. }
  101. // Announce to readers there is no active writer.
  102. r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
  103. if r >= rwmutexMaxReaders {
  104. raceEnable()
  105. panic("sync: Unlock of unlocked RWMutex")
  106. }
  107. // Unblock blocked readers, if any.
  108. for i := 0; i < int(r); i++ {
  109. runtime_Semrelease(&rw.readerSem)
  110. }
  111. // Allow other writers to proceed.
  112. rw.w.Unlock()
  113. if raceenabled {
  114. raceEnable()
  115. }
  116. }
  117. // RLocker returns a Locker interface that implements
  118. // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
  119. func (rw *RWMutex) RLocker() Locker {
  120. return (*rlocker)(rw)
  121. }
  122. type rlocker RWMutex
  123. func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
  124. func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }