Lesson 22 / 25
Data Races and the Race Detector
Unsynchronised access and how to catch it.
What counts as a data race
A data race happens when two goroutines access the same memory location concurrently, at least one access is a write, and nothing orders them (no channel operation, lock or atomic establishes a happens-before relationship under the Go memory model). Races cause lost updates, torn reads and, with maps, a runtime crash (concurrent map writes). Go ships a race detector: build or test with -race. It instruments memory accesses and reports races that actually occur during that run, with stack traces for both accesses, so it has no false positives but can miss races on code paths the run did not exercise. It makes programs noticeably slower and more memory-hungry, so run it in CI and in tests, and optionally in a canary, not across all production traffic. It needs cgo on some platforms; check the docs for supported systems.
Finding concurrency bugs before users do
Races, leaks and deadlocks are found with the race detector, goroutine profiles, leak checkers and deterministic tests.
A racy counter and the commands to catch it
counter++ is a read-modify-write, not an atomic operation.
// counter_test.go
package counter
import (
"sync"
"testing"
)
func TestCounter(t *testing.T) {
var wg sync.WaitGroup
count := 0
for range 100 {
wg.Add(1)
go func() {
defer wg.Done()
count++ // DATA RACE: unsynchronised read-modify-write
}()
}
wg.Wait()
if count != 100 {
t.Errorf("count = %d", count) // may pass or fail; -race flags it
}
}
// Fix: protect count with a sync.Mutex, or use an atomic.Int64.
//
// Commands (shell):
// go test -race ./...
// go run -race .
// go build -race -o app-race .Make -race part of CI
Run go test -race ./... on every change. Pair it with tests that really exercise concurrency (several goroutines, t.Parallel()), because the detector only sees races that happen during the run.
Quick check: Which statement about the Go race detector is accurate?
- It detects deadlocks rather than races
- It proves a program is race-free
- It runs at no extra cost, so it should always be on in production
- It reports only races that actually happen during the instrumented run
Answer
It reports only races that actually happen during the instrumented run — No false positives, but no guarantee either: coverage matters.