Ganso
Ganso

Reputation: 53

Mutex - global or local and idiomatic usage?

After reading the mutex examples on golang.org and stackoverflow, I'm still not sure about the declaration and idiomatic usage with anonymous functions. Therefore I've summarized a few examples.

Are examples A, B and C nearly equivalent or are there major differences that I don't notice? I would prefer the global example "B". I guess if I'm careful with it, it's probably the simplest solution.

Or is there maybe a better approach to use mutex?

This example on go playground

package main

import (
    "fmt"
    "sync"
)

type MuContainer struct {
    sync.RWMutex
    data int
}

var mucglobal = &MuContainer{}

func main() {

    // A: Global declaration - working: adds 45
    for i := 0; i < 10; i++ {
        go func(j int, mucf *MuContainer) {
            mucf.Lock()
            mucf.data += j
            mucf.Unlock()
        }(i, mucglobal)
    }

    // B: Global only - working: adds 45
    for i := 0; i < 10; i++ {
        go func(j int) {
            mucglobal.Lock()
            mucglobal.data += j
            mucglobal.Unlock()
        }(i)
    }

    // C: Local declaration - working: adds 45
    muclocal := &MuContainer{}
    for i := 0; i < 10; i++ {
        go func(j int, mucf *MuContainer) {
            mucf.Lock()
            mucf.data += j
            mucf.Unlock()
        }(i, muclocal)
    }

    // // D: Pointer to struct - not working: adds 0
    // // I guess because it points directly to the struct.
    // for i := 0; i < 10; i++ {
    //  go func(j int, mucf *MuContainer) {
    //      mucf.Lock()
    //      mucf.data += j
    //      mucf.Unlock()
    //  }(i, &MuContainer{})
    // }

    for {
        mucglobal.RLock()
        muclocal.RLock()
        fmt.Printf("global: %d / local: %d\n", mucglobal.data, muclocal.data)
        if mucglobal.data == 90 && muclocal.data == 45 {
            muclocal.RUnlock()
            mucglobal.RUnlock()
            break
        }
        muclocal.RUnlock()
        mucglobal.RUnlock()
    }
}

Upvotes: 0

Views: 901

Answers (1)

Burak Serdar
Burak Serdar

Reputation: 51592

D is not working because you are creating a new struct for each iteration. In the end, you'll have 10 independent instances of MuContainer.

The first two options are semantically identical. The bottom line for those two is that each goroutine shares the same instance of the object, which happens to be a global var.

The second one is similar with the only difference being the object locked and updated happens to be a local var. Again, the goroutines are working on the same instance of the object.

So these are not really different from each other, and all three have their uses.

Upvotes: 3

Related Questions