Senior · Concurrency
An atomic pointer publishes a mutable map
A writer atomically stores *Config, then updates Config.Limits while readers use it. Does atomic.Pointer make the map access safe?
Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.
package main
import (
"fmt"
"sync/atomic"
)
type Config struct{ limits map[string]int }
func publish(dst *atomic.Pointer[Config], src map[string]int) {
copied := make(map[string]int, len(src))
for k, v := range src {
copied[k] = v
}
dst.Store(&Config{limits: copied})
}
func main() {
var current atomic.Pointer[Config]
input := map[string]int{"workers": 4}
publish(¤t, input)
input["workers"] = 99
snapshot := current.Load()
fmt.Println(snapshot.limits["workers"]) // 4
}Reveal a strong answer
An atomic load or store synchronizes an operation on the atomic value. It does not recursively make the object graph immutable or protect a later map mutation. A useful read-mostly pattern builds a complete independent configuration, publishes one pointer and lets readers hold that immutable snapshot. All fields that must agree belong to the same published value.
Choose a mutex when operations update related state together; choose an atomic primitive only for a precisely defined protocol. Atomic types and mutexes must not be copied after first use. If a snapshot contains slices, pointers or nested maps, define deep-enough copying and lifetime rules. Compare this with sync.Map, whose per-operation contracts do not provide a transaction across arbitrary keys. The map is copied before the pointer is stored. Changing the caller’s input afterward does not mutate the published configuration. Readers load one pointer and keep that snapshot, rather than loading separate fields at different times. A production API should avoid exposing a mutable map from the snapshot to callers.
Publishing a pointer and then changing its map races with readers. Two independent atomic fields do not automatically form a consistent pair. Race detection finds executed data races, not every logical ordering error. Test concurrent publication/read behavior and business invariants with native go test -race; the app sandbox does not supply a native race detector.
Common trap
Atomic access to a pointer does not recursively apply atomicity to the entire object graph.
Try it
Construct a separate snapshot, copy reachable mutable state, publish once and test concurrent reads/publications natively.
Worked solution
Atomic publication protects the pointer protocol, not later mutations of referenced maps or slices. Build a deep-enough independent snapshot and keep its reachable state immutable, or synchronize all accesses with the same lock protocol. Load one snapshot for fields that must agree; two independent atomics do not create a multi-field transaction. Use native race tests and invariant checks, since absence of a reported race does not prove every logical guarantee.
Change the constraint
How should an API return part of the snapshot without giving callers a mutable map alias?
How did you do?
Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.
Not marked. Progress stays on this browser, separate from course completion.
Primary references
Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.