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?
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, containing 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.)