blob: c90a06154a18090f10fb1c679fbec7317e3d7818 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
# Mistake #71: Misusing sync.WaitGroup
Call `wg.Add` before spinning up goroutines, not inside them. Calling `Add` inside a goroutine introduces a race with `Wait`.
In the following example, `wg.Add(1)` is called within the newly created goroutine, not in the parent goroutine:
wg := sync.WaitGroup{}
var v uint64
for i := 0; i < 3; i++ {
go func() {
wg.Add(1)
atomic.AddUint64(&v, 1)
wg.Done()
}()
}
wg.Wait()
fmt.Println(v)
If we run this example, we get a non-deterministic value (0 to 3) and a data race. The problem is that there is no guarantee that we have indicated to the wait group that we want to wait for three goroutines before calling `wg.Wait()`.
To fix this, call `wg.Add` before the loop or inside the loop but not in the goroutine:
wg := sync.WaitGroup{}
var v uint64
wg.Add(3)
for i := 0; i < 3; i++ {
go func() {
atomic.AddUint64(&v, 1)
wg.Done()
}()
}
wg.Wait()
fmt.Println(v)
[Source code](https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/71-wait-group/main.go)
|