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.