goconcurrencylockingmutexwaitgroup

Printing map object when it is locked by mutex


I am not sure why mutex is not working as I expected. Any advice will help me.

Here is my code.

package main

import (
    "fmt"
    "sync"
    "time"
)

type Container struct {
    mu       sync.Mutex
    counters map[string]int
}

func (c *Container) inc(name string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.counters[name]++
    
    // fmt.Println("in", name, c.counters) 
    // This print is doing tricks between goroutines
    time.Sleep(time.Second)
}

func main() {
    c := Container{

        counters: map[string]int{"a": 0, "b": 0},
    }

    var wg sync.WaitGroup

    doIncrement := func(name string, n int) {
        for i := 0; i < n; i++ {
            c.inc(name)
            fmt.Println(name, c.counters)
        }
        wg.Done()
    }

    wg.Add(3)
    go doIncrement("a", 2)
    go doIncrement("b", 2)
    go doIncrement("a", 2)

    wg.Wait()
    fmt.Println(c.counters)
}

When I ran this, I got strange outputs.

a map[a:2 b:0]
a map[a:2 b:0]
b map[a:2 b:1]
a map[a:4 b:1]
a map[a:4 b:1]
b map[a:4 b:2]
map[a:4 b:2]

I expected some logs where I can see a increased to 1,2,3,4

When I removed comments in inc function; I could see the expected logs.

in a map[a:1 b:0]
a map[a:1 b:0]
in a map[a:2 b:0]
a map[a:2 b:0]
in b map[a:2 b:1]
b map[a:2 b:1]
in a map[a:3 b:1]
a map[a:3 b:1]
in a map[a:4 b:1]
a map[a:4 b:1]
in b map[a:4 b:2]
b map[a:4 b:2]
map[a:4 b:2]

Solution

  • In this loop:

    for i := 0; i < n; i++ {
                c.inc(name)  ---> This runs with mutex locked
                fmt.Println(name, c.counters)  --> This runs with mutex unlocked
    }
    

    The Println runs outside the mutex lock. Two goroutines attempt to increment "a" at the same time, one increments and then waits. When that increment function returns, the second one goes in and increments, then Println from the first one runs, then Println from the second one prints the same thing.

    So, mutex is working as expected, but you are printing outside the region protected by mutex.