Deterministic example for atomics.

Fixes #265
This commit is contained in:
Eli Bendersky
2019-09-05 10:50:09 -07:00
parent 13b0da17de
commit ef8f0e3831
4 changed files with 66 additions and 64 deletions

View File

@@ -7,9 +7,11 @@
package main
import "fmt"
import "time"
import "sync/atomic"
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
@@ -17,33 +19,28 @@ func main() {
// (always-positive) counter.
var ops uint64
// To simulate concurrent updates, we'll start 50
// goroutines that each increment the counter about
// once a millisecond.
// A WaitGroup will help us wait for all goroutines
// to finish their work.
var wg sync.WaitGroup
// We'll start 50 goroutines that each increment the
// counter exactly 1000 times.
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
for {
for c := 0; c < 1000; c++ {
// To atomically increment the counter we
// use `AddUint64`, giving it the memory
// address of our `ops` counter with the
// `&` syntax.
atomic.AddUint64(&ops, 1)
// Wait a bit between increments.
time.Sleep(time.Millisecond)
}
wg.Done()
}()
}
// Wait a second to allow some ops to accumulate.
time.Sleep(time.Second)
// In order to safely use the counter while it's still
// being updated by other goroutines, we extract a
// copy of the current value into `opsFinal` via
// `LoadUint64`. As above we need to give this
// function the memory address `&ops` from which to
// fetch the value.
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
// Wait until all the goroutines are done.
wg.Wait()
fmt.Println("ops:", ops)
}

View File

@@ -1,2 +1,2 @@
a4190094ea0405b5f2733101beb97939a1d43aee
KDr9EMMPMgi
103c9b7d036e3a5c14dc481755b78b10dc9f894e
GRkVf6J1--B

View File

@@ -1,7 +1,11 @@
# Running the program shows that we executed about
# 40,000 operations.
# We expect to get exactly 50,000 operations. Had we
# used the non-atomic `ops++` to increment the counter,
# we'd likely get a different number, changing between
# runs, because the goroutines would interfere with
# each other. Moreover, we'd get data race failures
# when running with the `-race` flag.
$ go run atomic-counters.go
ops: 41419
ops: 50000
# Next we'll look at mutexes, another tool for managing
# state.