Home > Software engineering >  Mutex lock does not work as expected. Is this expected result?
Mutex lock does not work as expected. Is this expected result?

Time:12-01

I am learning Go but I have good experience in C, C , javascript, etc.

And 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)
    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]

Can someone explain why this is happening?

CodePudding user response:

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.

  • Related