Skip to content

Commit 3173658

Browse files
committed
fix: add TryLock to sync.RWMutex
1 parent c769262 commit 3173658

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

src/sync/mutex.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type RWMutex struct {
3131

3232
const rwMutexMaxReaders = 1 << 30
3333

34+
// Lock locks rw for writing.
35+
// If the lock is already locked for reading or writing,
36+
// Lock blocks until the lock is available.
3437
func (rw *RWMutex) Lock() {
3538
// Exclusive lock for writers.
3639
rw.writerLock.Lock()
@@ -56,6 +59,12 @@ func (rw *RWMutex) Lock() {
5659
rw.writer.Store(0)
5760
}
5861

62+
// Unlock unlocks rw for writing. It is a run-time error if rw is
63+
// not locked for writing on entry to Unlock.
64+
//
65+
// As with Mutexes, a locked [RWMutex] is not associated with a particular
66+
// goroutine. One goroutine may [RWMutex.RLock] ([RWMutex.Lock]) a RWMutex and then
67+
// arrange for another goroutine to [RWMutex.RUnlock] ([RWMutex.Unlock]) it.
5968
func (rw *RWMutex) Unlock() {
6069
// Signal that new readers can lock this mutex.
6170
waiting := rw.readers.Add(rwMutexMaxReaders)
@@ -68,6 +77,31 @@ func (rw *RWMutex) Unlock() {
6877
rw.writerLock.Unlock()
6978
}
7079

80+
// TryLock tries to lock m and reports whether it succeeded.
81+
//
82+
// Note that while correct uses of TryLock do exist, they are rare,
83+
// and use of TryLock is often a sign of a deeper problem
84+
// in a particular use of mutexes.
85+
func (rw *RWMutex) TryLock() bool {
86+
// Check for active writers
87+
if !rw.writerLock.TryLock() {
88+
return false
89+
}
90+
// Have write lock, now check for active readers
91+
n := uint32(rwMutexMaxReaders)
92+
if !rw.readers.CompareAndSwap(0, -n) {
93+
// Active readers, give up write lock
94+
rw.writerLock.Unlock()
95+
return false
96+
}
97+
return true
98+
}
99+
100+
// RLock locks rw for reading.
101+
//
102+
// It should not be used for recursive read locking; a blocked Lock
103+
// call excludes new readers from acquiring the lock. See the
104+
// documentation on the [RWMutex] type.
71105
func (rw *RWMutex) RLock() {
72106
// Add us as a reader.
73107
newVal := rw.readers.Add(1)
@@ -79,6 +113,10 @@ func (rw *RWMutex) RLock() {
79113
}
80114
}
81115

116+
// RUnlock undoes a single [RWMutex.RLock] call;
117+
// it does not affect other simultaneous readers.
118+
// It is a run-time error if rw is not locked for reading
119+
// on entry to RUnlock.
82120
func (rw *RWMutex) RUnlock() {
83121
// Remove us as a reader.
84122
one := uint32(1)
@@ -98,6 +136,25 @@ func (rw *RWMutex) RUnlock() {
98136
}
99137
}
100138

139+
// TryRLock tries to lock rw for reading and reports whether it succeeded.
140+
//
141+
// Note that while correct uses of TryRLock do exist, they are rare,
142+
// and use of TryRLock is often a sign of a deeper problem
143+
// in a particular use of mutexes.
144+
func (rw *RWMutex) TryRLock() bool {
145+
for {
146+
c := rw.readers.Load()
147+
if c < 0 {
148+
// There is a writer waiting or writing.
149+
return false
150+
}
151+
if rw.readers.CompareAndSwap(c, c+1) {
152+
// Read lock obtained.
153+
return true
154+
}
155+
}
156+
}
157+
101158
type Locker interface {
102159
Lock()
103160
Unlock()

0 commit comments

Comments
 (0)