Atomics
Use atomics only when you can state the synchronization story precisely; prefer mutexes first.
Canonical guidance
- prefer mutexes unless a simple atomic primitive clearly suffices
- use atomics for narrow cases like flags, counters, and pointers with precise semantics
- reason in terms of synchronization and visibility, not speed folklore
Use when
- single-value shared state
- fast-path flags
- lock-free structures only with strong expertise and tests
Avoid
- combining many atomics into a pseudo-transaction
- using atomics without understanding the required ordering
- assuming atomics automatically simplify code
Preferred pattern
type Gate struct {
ready atomic.Bool
}
func (g *Gate) MarkReady() {
g.ready.Store(true)
}
func (g *Gate) Ready() bool {
return g.ready.Load()
}
Anti-pattern
- large state machines encoded through scattered atomic loads and stores
Explanation: This anti-pattern is tempting because atomics look cheaper than locks, but scattered loads and stores usually hide correctness bugs behind superficial performance intuition.
Why
- atomics trade simplicity for lower-level control
- misuse creates subtle concurrency bugs
Related pages
Sources
- sync/atomic package - Go Team
- The Go Memory Model - Go Team