-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sync: document more clearly sync.RWMutex doesn't support lock upgrades/downgrades #38859
Comments
Thanks, but I'm not in favor of this, because I would say that |
@ianlancetaylor Normally, I find the Go standard library documentation to be very instructive as to the correct way to use it, so I was surprised that It is true that there is no atomic upgrade or downgrade, but this is not mentioned at all. At the very least, I think it would be useful to mention this in the doc comment. My request for an example is to provide guidance on how to use In fact, there is a subtle bug in my example where two func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
m.mu.RLock()
defer m.mu.RUnlock()
loaded = true
// Retry until actual can be read from m.data so the first LoadOrStore wins:
for ok := false; !ok; {
if actual, ok = m.data[key]; ok {
break
}
// Upgrade the read lock to a write lock:
m.mu.RUnlock()
m.mu.Lock()
if m.data == nil {
m.data = make(map[interface{}]interface{})
}
// Upgrading the lock is not atomic, so another writer may have raced us:
if _, ok := m.data[key]; !ok {
m.data[key] = value
loaded = false
}
// Downgrade the write lock to a read lock:
m.mu.Unlock()
m.mu.RLock()
}
return actual, loaded
} |
Have you benchmarked this? Is it faster than a single map plus mutex or striped mutex? |
@davecheney: Sorry if I wasn’t clear: the exact example does not matter. We can substitute any example that protects something with many readers and a single writer. This feature request is to add an example for how to safely upgrade and downgrade a write lock on |
I suggest simply stating in the RWMutex documentation that it does not support upgrading or downgrading locks. The text right now seems to be trying to say that, but it's honestly hard to follow:
How about this instead:
We can then provide an example that shows that because upgrades are impossible it is important to take into account that other goroutines may acquire a lock between a call to RUnlock and Lock. It basically means that if you're trying to do a CAS-style atomic operation then you must repeat the comparision after the Lock, because the state may very well have changed between the RUnlock and the Lock. |
I agree 100% that this should be made clearer in the documentation. It's still not clear enough. |
Change https://go.dev/cl/633415 mentions this issue: |
What version of Go are you using (
go version
)?What did you do?
Tried to figure out the correct semantics for upgrading and downgrading read and write locks in
sync.RWMutex
.What did you expect to see?
Unlike
sync.Mutex
, working withsync.RWMutex
is a bit tricky especially when it comes to upgrading and downgrading read and write locks. #4026 documents how one should perform these operations, but this isn’t linked in the documentation itself.I propose an example that demonstrates upgrading and downgrading locks. Maybe something like this?
The text was updated successfully, but these errors were encountered: