×

go · level 3 · unit 4 · lesson 2

  1. meet it
  2. guess first
  3. your turn
  4. fix it
  5. nailed it

Tap a green word if you get lost.

meet it

A lets one goroutine at a time into the shared data.

A mutex, sync.Mutex, is a with one key. mu.Lock() takes the key, waiting if another goroutine has it, and mu.Unlock() hands it back. The code between them is a : only one goroutine can be inside at once, so count++ can no longer lose updates.

Write defer mu.Unlock() straight after Lock, so the key comes back however the function ends, even through a panic. Keep each critical section short, because everyone else queues while you hold the key.

Keep the mutex in a struct right beside the data it guards, and give the struct pointer-receiver methods. A copied mutex is a different lock guarding a different copy of the data.

package main
import (
	"fmt"
	"sync"
)
type Counter struct {
	mu    sync.Mutex
	votes map[string]int
}
func (c *Counter) Vote(name string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.votes[name]++
}
func main() {
	c := Counter{votes: map[string]int{}}
	var wg sync.WaitGroup
	for _, v := range []string{"cats", "dogs", "cats", "cats", "dogs"} {
		wg.Add(1)
		go func(v string) { defer wg.Done(); c.Vote(v) }(v)
	}
	wg.Wait()
	fmt.Println(c.votes)
}

Without the mutex, two goroutines writing one map at once can crash the program outright.