What are typed atomics (atomic.Int64, atomic.Pointer[T]) and why prefer them over atomic.AddInt64 / atomic.Value?
Question 230MediumGo 1.22 to 1.25
Go 1.19 added atomic.Int32, Int64, Uint32, Uint64, Uintptr, Bool and Pointer[T]. They are better than the function-based API for three reasons:
- No accidental non-atomic access: the value can only be reached through methods. With a plain
int64it is easy to writex++somewhere and create a race. - Alignment:
atomic.Int64andUint64are guaranteed 64-bit aligned even on 32-bit platforms (386, ARM).atomic.AddInt64on a misaligned field panics there. - Type safety:
atomic.Pointer[T]replacesatomic.Value.atomic.Valuepanics onStore(nil)and on storing inconsistent concrete types, and it needs a type assertion on everyLoad.
type Server struct {
requests atomic.Int64
cfg atomic.Pointer[Config] // copy-on-write config
}
func (s *Server) Handle() {
s.requests.Add(1)
cfg := s.cfg.Load() // lock-free read of an immutable snapshot
_ = cfg.Timeout
}
func (s *Server) Reload(c *Config) { s.cfg.Store(c) }
Go 1.23 added And and Or methods on the integer types.
What the interviewer is looking for: the snapshot behind an atomic.Pointer must be treated as immutable. Mutating *cfg after Store is a data race.
More on Concurrency Patterns & sync
- Q228How does sync.Pool work, how does it interact with the GC, and what are the common misuse pitfalls?
- Q229When should you use sync.Map instead of a map guarded by a Mutex?
- Q231Implement a lock-free "store max" using compare-and-swap. What is the ABA problem, and does it affect Go?
- Q232Explain the Go memory model and "happens-before". What synchronization edges does Go guarantee?
- Q233What does this program print?
- Q234How does the race detector work, and what are its limitations? Is a "benign" data race ever OK?