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
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


