32

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?

2
  • 3
    Your first example doesn't work, because you can't call the method expression on A without an explicit receiver. If you're asking about using a single mutex per struct instance, or a single global mutex; do you need global mutex or do you want to lock each instance individually? It depends on what you're trying to accomplish.
    – JimB
    Jul 6, 2017 at 13:14
  • Thank you. I changed my code. Jul 6, 2017 at 14:09

1 Answer 1

75

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.)

3
  • Some times I am sad that I could not add 10 or 50 likes per message. When found some hidden syntax of a language it usually such joy to found explanation and links to the official documentation of this language. Even Golang has such syntax entities, other language has much more. Jan 28 at 8:27
  • It is important never to copy the hits variable, correct? Feb 21 at 6:59
  • 1
    @TorstenBronger Yes, a mutex must not be copied. If you need to pass hits around, make it a pointer and pass the pointer.
    – icza
    Feb 21 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.