Atomic Operations
debt(d8/e3/b4/t7)
Closest to 'silent in production until users hit it' (d9, scored 8). Race conditions from non-atomic read-modify-write sequences rarely surface in testing — detection_hints.automated is 'no' and the code pattern (get.*set|read.*write) is too generic for reliable static detection. Only manifests under concurrent load.
Closest to 'simple parameterised fix' (e3). Per quick_fix, replacing read-modify-write with INCR or a single UPDATE is a localized pattern swap, slightly more involved than one-line because it requires understanding the surrounding logic.
Closest to 'localised tax' (b3, scored 4). Applies across web/cli/queue-worker contexts so reach is moderate; counters and shared state touched by atomicity concerns can ripple but each fix is contained per call site.
Closest to 'serious trap' (t7). The misconception that 'all database operations are atomic' and that PHP's $++ is atomic on shared resources contradicts how developers reason from single-threaded intuition — the obvious read-then-write code looks correct but silently corrupts under concurrency.
TL;DR
Explanation
Atomic operations: indivisible at the hardware or software level. Examples: Redis INCR (read-increment-write as one operation), database UPDATE counter = counter + 1 (single statement), CAS (compare-and-swap), PHP intl_atomic functions. Non-atomic example: PHP $counter++ on a shared file (read, increment, write — three separate ops). Atomicity levels: hardware (CPU atomic instructions), database (single SQL statement), application (transaction). For counters: use Redis INCR, DB UPDATE ... + 1, or INCR with MULTI/EXEC. Atomic operations don't require mutex — they're inherently safe.
Common Misconception
Why It Matters
Common Mistakes
- Using read-then-write where a single atomic update would suffice.
- Treating PHP $++ as atomic — it's not on shared resources.
- Not using Redis INCR/DECR for counters that need atomic increment.
Code Examples
// Non-atomic — race condition:
$views = $redis->get('views');
$redis->set('views', $views + 1); // Lost updates under load
// Atomic:
$views = $redis->incr('views'); // Single command — atomic
// DB atomic update:
$pdo->execute('UPDATE stats SET views = views + 1 WHERE slug = ?', [$slug]);
// CAS-style:
$updated = $pdo->execute(
'UPDATE inventory SET qty = qty - 1 WHERE id = ? AND qty > 0',
[$productId]
);
if (!$updated) throw new OutOfStockException();