Compare-and-Swap (CAS)
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and semgrep is listed but catching race conditions from missing CAS/version checks requires semantic understanding of concurrent access patterns. Code patterns like 'read-modify-write without atomic operation' are difficult to detect statically — typically only manifests under concurrent load testing or production race conditions.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix shows a database-level solution with optimistic locking (version column), which requires schema changes, updating all write queries to include version checks, and adding retry logic. While a single CAS call is simple, properly implementing CAS patterns across a component involves retry loops, backoff strategies, and potentially restructuring how concurrent updates are handled.
Closest to 'persistent productivity tax' (b5). CAS applies across web/cli/queue-worker contexts and once chosen as a concurrency strategy, it imposes ongoing maintenance burden — every concurrent update path must correctly implement CAS patterns, handle failures, implement backoff, and avoid the ABA problem. Teams must understand the tradeoffs versus mutex-based approaches, creating a persistent knowledge tax.
Closest to 'serious trap' (t7). The misconception explicitly states developers wrongly believe 'Mutex locks and CAS are interchangeable' when they behave very differently — CAS retries without blocking, making it efficient under low contention but wasteful under high contention. This contradicts intuition from lock-based concurrency. Common mistakes include infinite retry loops without backoff and ignoring the ABA problem, both stemming from misunderstanding CAS semantics.
Also Known As
TL;DR
Explanation
CAS (Compare-And-Swap) is an atomic operation: atomically read a value, compare to expected, and write a new value only if it matches. If another thread changed the value between the read and write, CAS fails and the operation retries. This is the foundation of: lock-free programming, optimistic locking in databases (UPDATE WHERE version=expected), Redis WATCH/MULTI/EXEC transactions, and atomic counters. PHP: apcu_cas() provides CAS for APCu cache. The ABA problem: CAS can succeed incorrectly if a value changes A→B→A between operations — use versioned counters to prevent.
Common Misconception
Why It Matters
Common Mistakes
- Infinite retry loop without backoff — under high contention, CAS spins and wastes CPU.
- Not handling CAS failure — apcu_cas() returns false if the value changed; must retry.
- ABA problem in long-lived CAS loops — include a version counter alongside the value.
- Using CAS for complex multi-step operations — CAS is for single-value atomic updates; use transactions for multiple.
Code Examples
// Non-atomic rate limiter — race condition:
$count = apcu_fetch('rate:' . $ip); // Read
$count++; // Increment
apcu_store('rate:' . $ip, $count); // Write
// Two concurrent requests both read 0, both write 1
// Counter never exceeds 1 regardless of requests
// Atomic CAS rate limiter:
function atomicIncrement(string $key, int $max): bool {
for ($attempts = 0; $attempts < 10; $attempts++) {
$current = apcu_fetch($key);
if ($current === false) {
apcu_add($key, 1, 60); // Set to 1 with 60s TTL
return true;
}
if ($current >= $max) return false; // Rate limited
if (apcu_cas($key, $current, $current + 1)) return true; // Atomic!
usleep(100); // Brief backoff before retry
}
return false;
}