liveBook · Manning

Compare-and-exchange operation

As explained in Learn Concurrent Programming with Go

Compare-and-swap is an atomic operation that compares a memory location with an expected value and replaces it with a new value only when they match, returning whether the replacement occurred.

A compare-and-exchange operation updates a shared value only if it still equals an expected value. It takes a pointer plus old and new values: when the stored value matches old, it writes new and returns true; otherwise it leaves the value unchanged and returns false. Because the check and update are atomic, another execution cannot interrupt between them. section 12.2.1

Figure 12.4 The CompareAndSwap() function operating in two scenarios

View the success path, where an expected value becomes a new value, beside the failure path, where a mismatch preserves the current value. section 12.2.1

Testing an expected value

With an integer holding 17, CompareAndSwapInt32(&number, 17, 19) succeeds, returns true, and changes the value to 19. If the integer instead holds 23, the same request returns false and leaves it at 23. The boolean result tells the caller whether it won the attempted update. section 12.2.1

A lock can use compare-and-exchange as a single shared flag: 0 means free and 1 means locked. Attempt CompareAndSwap(0, 1) to acquire it. Success claims the lock; failure means another goroutine already holds it. Retrying until success produces a spin lock, while Unlock stores 0 to release the flag. section 12.2.2

Choose the surrounding strategy based on contention:

  • Spin and optionally yield to the Go scheduler when the lock is held, giving another goroutine a chance to run and release it. section 12.2.2
  • Use a futex-oriented path when contention occurs: a failed initial compare-and-exchange leads to marking waiters and suspending execution rather than looping continuously. section 12.3.2
  • Recognize the limit of atomic variables: they protect one variable at a time; coordinated updates across multiple variables need a mutex or another synchronization tool. section 12.5

Compare-and-exchange also supports a fast path in semaphore and mutex internals. A semaphore first reads available permits and atomically tries to reduce one; if no permit is available, the goroutine is queued and parked. This avoids treating every failed acquisition as busy waiting. section 12.3.3

How Learn Concurrent Programming with Go covers it

How deep it goes
Defines success and failure semantics, then works through spin-lock and semaphore acquisition paths without detailing full runtime edge cases.
Examples
Demonstrates integer swaps from 17 to 19, a 0/1 spin-lock flag, and semaphore permit acquisition pseudocode.
What it assumes
Introduces compare-and-exchange behavior directly while using Go atomic variables, goroutines, and synchronization primitives.
What you can do after
Build it from scratch as a compare-and-exchange-based spin lock and choose waiting mechanisms when contention makes spinning wasteful.
How it connects
Connects atomic variables with spin locks, mutexes, futexes, semaphores, goroutines, and race conditions.

Also explained in

Compare how 3 books explain compare-and-exchange operation →

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.