-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
proposal: sync: add Mutex.Do #63941
Comments
The same would apply to |
For |
Alternatively, we could do: func WithLock(lock Locker, f func()) {
lock.Lock()
defer lock.Unlock()
f()
}
func WithLockValue[T any](lock Locker, f func() T) T {
lock.Lock()
defer lock.Unlock()
return f()
}
func WithLockValues[T1, T2 any](lock Locker, f func() (T1, T2)) (T1, T2) {
lock.Lock()
defer lock.Unlock()
return f()
} This avoids methods on m.Do(func() { ... }) versus sync.WithLock(&m, func() { ... }) However, it has the advantage that we can declare the |
Already supported. func(){
m.Lock()
defer m.Unlock()
...
}() You can use it in locks, or in shorter sections of a function, to scope it shorter. |
An alternative design for sync/v2 would be to have Mutex protect generic values like this: https://github.com/carlmjohnson/syncx/blob/main/mutex.go It’s more like Rust in that you can’t misuse the protected value. |
@carlmjohnson This is not good. It is too restrictive. You often need to access more complex types (i.e. maps) while holding a mutex, do read-modify-write operation, change multiple values, keep lock held, when calling a function, etc. Such wrapper to protect one variable is only a trouble. From my experience in Go, C++, D, such generic protected value, is more trouble than a solution, and in majority of cases is not enough. |
I have seen type X struct {
sync.Mutex
// ...
} This isn't a good practice if the type is public, but we must consider how adding a method would impact those cases. Edit: You can find many such cases in private types in stdlib: $ grep -lR '\tsync.Mutex$' src | wc -l
26 |
In the design of my package, you would write |
I quite like this design and think it's overall a better solution to the problem being addressed by this proposal, but I think that it should be an alternative to the current It is notable, though, that |
I feel this is just a poor man's workaround for scoped |
Here is an alternate naming scheme for the func Locked[L Locker](lock L, f func()) {
lock.Lock()
defer lock.Unlock()
f()
}
type RLocker interface {
RLock()
RUnlock()
}
func RLocked[L RLocker](lock L, f func()) {
lock.RLock()
defer lock.RUnlock()
f()
} Usage: sync.Locked(&m, func() {
// ...
})
sync.RLocked(&m, func() {
// ...
}) |
If these functions are so simple, then you can add it to your project, and start using them. They do not add much value being in a standard library. |
Shouldn't it be a "push" iterator of type
(Rubyists, I'm kidding.) |
it does feel a bit like singleflight.Do without the sharding and result reuse |
func() {
mu.Lock()
defer mu.Unlock()
// ...
}() I think we should do this, people already frequently use the above pattern as demonstrated by 10k hits on github |
I propose the following helper method being added to
Mutex
:Rationale
I was investigating a sluggish program and the result was because
defer m.Unlock()
is function scoped.Consider the following snippet:
Initially when
doSomething
was written it was concise and short such thats.mu.Lock()
and the correspondingdefer s.mu.Unlock()
concisely protected the body of the function. However, as usually goes with software engineering, this function grew in complexity such that logic was added that doesn't care about the resource protected bys.mu
. We are now unnecessarily holding the mutex for much longer than necessary (sincedefer s.mu.Unlock()
doesn't run until the function returns). This problem gets worse over time as the unrelated logic grows since thes.mu
operations get push father away (in terms of code locality) hiding it's existence and the runtime complexity of the unrelated logic grows as well.With a
Do
method, the scope of the critical region becomes clear:The text was updated successfully, but these errors were encountered: