In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple goroutines. |
|
![]() ![]() package main |
|
import ( "fmt" "sync" ) |
|
Container holds a map of counters; since we want to
update it concurrently from multiple goroutines, we
add a |
type Container struct { mu sync.Mutex counters map[string]int } |
Lock the mutex before accessing |
func (c *Container) inc(name string) { |
c.mu.Lock() defer c.mu.Unlock() c.counters[name]++ } |
|
Note that the zero value of a mutex is usable as-is, so no initialization is required here. |
func main() { c := Container{ |
counters: map[string]int{"a": 0, "b": 0}, } |
|
var wg sync.WaitGroup |
|
This function increments a named counter in a loop. |
doIncrement := func(name string, n int) { for i := 0; i < n; i++ { c.inc(name) } wg.Done() } |
Run several goroutines concurrently; note
that they all access the same |
wg.Add(3) go doIncrement("a", 10000) go doIncrement("a", 10000) go doIncrement("b", 10000) |
Wait for the goroutines to finish |
wg.Wait() fmt.Println(c.counters) } |
Running the program shows that the counters updated as expected. |
$ go run mutexes.go map[a:20000 b:10000] |
Next we’ll look at implementing this same state management task using only goroutines and channels. |
Next example: Stateful Goroutines.