NOTE: I found the word 'embed' in the title was bad choice, but I will keep it.
I see a lot of code does like this:
type A struct {
mu sync.Mutex
...
}
And use it like this:
a := &A{}
a.mu.Lock()
defer a.mu.Unlock()
a.Something()
Is it better than local mutex or global mutex?
a := &A{}
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()
a.Something()
When should I use former, or later?
Adding the mutex to the struct as a field, you will naturally have a separate mutex for each distinct struct values, responsible to guard that single, wrapper struct value (or its fields). Although adding a mutex as in your example is not embedding, it's a regular, named field.
A Mutex is used to provide a locking mechanism to ensure that only one Goroutine is running the critical section of code at any point in time to prevent race conditions from happening. Mutex is available in the sync package. There are two methods defined on Mutex namely Lock and Unlock.
Any code present between a call to Lock and Unlock will be executed by only one Goroutine. If one Goroutine already has the lock and if a new Goroutine is trying to get the lock, then the new Goroutine will be stopped until the mutex is unlocked.
A mutex does not need initialization.
It's good practice to keep the mutex close to the data it is destined to protect. If a mutex ought to protect concurrent access to fields of a struct value, it's very convenient to add the mutex as a field of that struct, so its purpose is obvious.
If in your app there is only a single "instance" of A
, it's fine to make the mutex a global variable too.
If your app is to create multiple values of A
, all of which needs to be protected from concurrent access (but only individually, multiple values may be accessed concurrently), then obviously a global mutex is a bad choice, it would limit the concurrent access to a single value of A
in any point in time.
Adding the mutex to the struct as a field, you will naturally have a separate mutex for each distinct struct values, responsible to guard that single, wrapper struct value (or its fields).
Although adding a mutex as in your example is not embedding, it's a regular, named field. An embedded field declaration omits the field name.
It's known and used to a lesser extent, but it's also handy that you can "truly" embed a mutex in a struct, and you can call Lock()
and Unlock()
as if they would be part of the struct itself. It looks like this:
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
(This example is taken from 10 things you (probably) don't know about Go, slide #3.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With