liveBook · Manning

Atomicity

As explained in Learn Concurrent Programming with Go

An atomic operation is an indivisible operation that cannot be interrupted during its execution.

Atomicity means indivisibility: an atomic operation cannot be interrupted while it executes. This matters when goroutines share state. A seemingly simple update such as money += 10 is compiled into multiple instructions, so another goroutine can slip between the read and write, producing a race condition and an unpredictable final balance. The instructions that must avoid such interference form a critical section. section 3.3.1

Figure 3.10 A race condition with two goroutines

Follow the interleaved reads and writes that let a deposit and withdrawal leave an incorrect balance. section 3.3.1

Atomic variables make selected single-variable operations complete as one uninterrupted update. Concurrent atomic additions do not interfere: each completed update is fully applied. In Go, sync/atomic operations take a pointer to the target variable; AddInt32 updates a counter, and LoadInt32 reads it. This can replace a mutex when the protected work is only one variable update. section 12.1.1

Fixing the shared bank balance

Run Stingy and Spendy with an int32 balance. Have each goroutine call atomic.AddInt32(&money, 10) or atomic.AddInt32(&money, -10), wait for both with a WaitGroup, then call atomic.LoadInt32(&money). The expected final balance remains 100 because each increment and decrement is indivisible. section 12.1.1

Atomicity is narrow. Atomic variables protect one variable at a time, not a multi-step or multi-variable transaction. Counting letter frequencies works because every update changes one slice element. Booking several flights together does not: all seat values must be checked and updated as one unit, so a mutex or another synchronization tool is needed. section 12.1.3 section 12.2

Use atomics deliberately rather than everywhere. Atomic updates are slower than normal updates because they must keep parallel executions able to observe changes; a benchmark shown for 64-bit addition reports atomic addition at more than three times the normal-update cost on that system. Results vary by system and architecture. section 12.1.2

How Learn Concurrent Programming with Go covers it

How deep it goes
Defines indivisible operations, traces a race, and demonstrates Go atomic updates, while deferring multi-variable protection to mutexes.
Examples
Uses a shared bank balance, a concurrent letter-frequency counter, and multi-flight booking to contrast suitable and unsuitable cases.
What it assumes
Introduces atomicity through shared goroutines and variables while building on prior familiarity with mutex-protected state.
What you can do after
Apply it via Go's sync/atomic package for single-variable additions, loads, stores, swaps, and compare-and-swap operations.
How it connects
Connects atomicity with race conditions, critical sections, mutexes, goroutines, spin locks, and futexes.

Also explained in

Compare how 13 books explain atomicity →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Concurrent Programming with Go. The section links point to the parts of the book it draws on.