Skip to content

Commit ef8f0e3

Browse files
committed
Deterministic example for atomics.
Fixes mmcgrana#265
1 parent 13b0da1 commit ef8f0e3

File tree

4 files changed

+63
-61
lines changed

4 files changed

+63
-61
lines changed

examples/atomic-counters/atomic-counters.go

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,40 @@
77

88
package main
99

10-
import "fmt"
11-
import "time"
12-
import "sync/atomic"
10+
import (
11+
"fmt"
12+
"sync"
13+
"sync/atomic"
14+
)
1315

1416
func main() {
1517

1618
// We'll use an unsigned integer to represent our
1719
// (always-positive) counter.
1820
var ops uint64
1921

20-
// To simulate concurrent updates, we'll start 50
21-
// goroutines that each increment the counter about
22-
// once a millisecond.
22+
// A WaitGroup will help us wait for all goroutines
23+
// to finish their work.
24+
var wg sync.WaitGroup
25+
26+
// We'll start 50 goroutines that each increment the
27+
// counter exactly 1000 times.
2328
for i := 0; i < 50; i++ {
29+
wg.Add(1)
30+
2431
go func() {
25-
for {
32+
for c := 0; c < 1000; c++ {
2633
// To atomically increment the counter we
2734
// use `AddUint64`, giving it the memory
2835
// address of our `ops` counter with the
2936
// `&` syntax.
3037
atomic.AddUint64(&ops, 1)
31-
32-
// Wait a bit between increments.
33-
time.Sleep(time.Millisecond)
3438
}
39+
wg.Done()
3540
}()
3641
}
3742

38-
// Wait a second to allow some ops to accumulate.
39-
time.Sleep(time.Second)
40-
41-
// In order to safely use the counter while it's still
42-
// being updated by other goroutines, we extract a
43-
// copy of the current value into `opsFinal` via
44-
// `LoadUint64`. As above we need to give this
45-
// function the memory address `&ops` from which to
46-
// fetch the value.
47-
opsFinal := atomic.LoadUint64(&ops)
48-
fmt.Println("ops:", opsFinal)
43+
// Wait until all the goroutines are done.
44+
wg.Wait()
45+
fmt.Println("ops:", ops)
4946
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
a4190094ea0405b5f2733101beb97939a1d43aee
2-
KDr9EMMPMgi
1+
103c9b7d036e3a5c14dc481755b78b10dc9f894e
2+
GRkVf6J1--B
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
# Running the program shows that we executed about
2-
# 40,000 operations.
1+
# We expect to get exactly 50,000 operations. Had we
2+
# used the non-atomic `ops++` to increment the counter,
3+
# we'd likely get a different number, changing between
4+
# runs, because the goroutines would interfere with
5+
# each other. Moreover, we'd get data race failures
6+
# when running with the `-race` flag.
37
$ go run atomic-counters.go
4-
ops: 41419
8+
ops: 50000
59

610
# Next we'll look at mutexes, another tool for managing
711
# state.

public/atomic-counters

Lines changed: 36 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)