Lock-Free & Wait-Free Programming

load-linked / store-conditional (LL/SC)

/ EL-EL-ES-SEE /

Compare-and-swap asks one question — is the value still what I expected? — but it answers it by comparing bits, which can be fooled if the value changed and changed back. LL/SC is a different hardware primitive, used on ARM, RISC-V, POWER, and MIPS, that instead asks a sharper question: has this location been written AT ALL since I last looked? It is built from a pair of instructions that work together.

Here is the dance. Load-linked (LL) reads a memory location and quietly tells the hardware to start watching that address — it sets a hidden reservation. You then compute your new value in ordinary registers. Finally, store-conditional (SC) attempts to write back, but it succeeds only if nothing has written to that address since your LL; otherwise it writes nothing and reports failure. The crucial difference from CAS is that SC fails if there was ANY intervening write, even a write that restored the exact same value. That is why LL/SC sidesteps the ABA problem that bites plain CAS: it watches for the write event itself, not for a change in the final value. As with weak CAS, you wrap it in a retry loop.

The honest catch is that the reservation is fragile. SC is allowed to fail spuriously for reasons unrelated to your data — a context switch, an interrupt, another access to the same cache line, or simply touching memory between the LL and SC. So portable code keeps the LL-to-SC window tiny: a couple of register operations, no function calls, no other loads or stores. Because of this fragility, higher-level languages expose CAS, not LL/SC, and compilers synthesise compare-and-swap on top of LL/SC on the machines that have it.

; AArch64 atomic increment built from LL/SC, retried until STXR succeeds. loop: ldxr x1, [x0] ; load-linked: read and set reservation on [x0] add x1, x1, #1 ; compute new value stxr w2, x1, [x0] ; store-conditional: w2 = 0 if it succeeded cbnz w2, loop ; if w2 != 0 the SC failed, so retry

STXR succeeds only if nothing wrote to the address since LDXR — including a write that restored the same value, which is why LL/SC is naturally ABA-immune.

SC may fail spuriously for reasons unrelated to your value (interrupts, cache-line traffic), so keep the LL-to-SC window tiny and always loop. LL/SC avoids ABA by watching for any write, not for a value change.

Also called
LL/SCLDREX/STREXLDXR/STXRlr/sc連結載入條件儲存