Go

Implement a lock-free "store max" using compare-and-swap. What is the ABA problem, and does it affect Go?

Question 231HardGo 1.22 to 1.25
func StoreMax(a *atomic.Int64, v int64) {
	for {
		cur := a.Load()
		if v <= cur {
			return
		}
		if a.CompareAndSwap(cur, v) {
			return
		}
		// another goroutine changed it: reload and retry
	}
}

A CAS loop reads the current value, computes a new one, and swaps only if the value is still unchanged. If the swap fails it retries. Under heavy contention the loop can spin many times. For a simple sum, Add is better because it maps to a single hardware instruction (LOCK XADD).

ABA problem: a value changes from A to B and back to A between your Load and your CAS. The CAS succeeds even though the state changed underneath you. This matters most for lock-free stacks, where a node gets popped, freed, reused and pushed again.

In Go: the garbage collector mostly removes the memory-reuse variant. A node's address cannot be recycled while your goroutine still holds a pointer to it. Logical ABA is still possible with integer values or with explicitly pooled nodes, for example through sync.Pool. Common fixes are version counters or immutable nodes.

Interview tip: say that you reach for lock-free code only after profiling. A mutex is usually fast enough and much easier to reason about.

More on Concurrency Patterns & sync

All 38 Concurrency Patterns & sync questions