gostructconcurrencymutex

Multiple mutexes in same struct?


I have a few related questions about Go's sync.Mutex used with struct. If I were to, for instance, have this struct:

type something struct {
    aMux sync.Mutex
    a    map[string]interface{}

    bMux sync.Mutex
    b    int
}

... would it be safe to lock bMux and access b while concurrently locking aMux and accessing a without a race condition?

It's probably also helpful to know that I'm accessing pointers to the structs, and using methods like this to lock/unlock the mutexes concurrently:

func (s *something) addA(k string, v interface{}) {
    (*s).aMux.Lock()
    (*s).a[k] = v
    (*s).aMux.Unlock()
}

func (s *something) addB(k string, v interface{}) {
    (*s).bMux.Lock()
    (*s).b++
    (*s).bMux.Unlock()
}

My assumption is that this should theoretically be safe, since you can already lock a mutex in a struct without having to access the field(s) it locks. But when dereferencing a struct like above, does Go copy all the values from the struct (making it unsafe), or does it only modify/retrieve the fields you specify?

I would very much like to keep the mutexes in the same struct, since in my code I have multiple (up to six) related fields in the same struct that I lock separately with mutexes. If having multiple mutexes in the same struct (for related fields) is safe, but not recommended or bad practice, why? What would be a better structure?


Solution

  • It should be safe to have multiple mutexes in a single struct. Just be careful not to pass the struct by value because mutexes are not reference types and copying them is wrong (see this discussion for more details).

    You do not need the explicit dereferencing, Go does it for you:

    func (s *something) addA(k string, v interface{}) {
        s.aMux.Lock()
        s.a[k] = v
        s.aMux.Unlock()
    }
    

    Should work just as well (it's in the Go tour).

    I would say it's not very usual design though. I'd prefer a mutex to lock the whole structure if possible. Once you're doing very fine grained locking you have to be extremely careful, and I would explore other options first.