← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Race Condition

concurrency Intermediate

TL;DR

A race condition occurs when the outcome of a program depends on the relative timing of concurrent operations — two threads reading and writing shared state without coordination.

Explanation

Race conditions arise when multiple threads/processes access shared mutable state without synchronisation. Classic example: two threads both read a counter (value: 5), both increment locally, both write (both write 6 instead of 7). The TOCTOU (Time-Of-Check-To-Time-Of-Use) variant: check a condition then act on it, but state changes between check and act. In PHP: race conditions occur in file-based counters (read→increment→write without locks), cache stampede (multiple processes regenerating expired cache simultaneously), and database reads without transactions. Prevention: atomic operations, mutexes/locks, database transactions, optimistic locking.

Common Misconception

Race conditions only happen in multi-threaded languages — PHP-FPM runs many processes concurrently, all sharing files, databases, and caches. Race conditions are very real in PHP.

Why It Matters

Race conditions cause intermittent data corruption that's extremely hard to reproduce and debug — they typically surface under load when multiple requests hit the same code path simultaneously.

Common Mistakes

  • File-based counters without flock() — classic race condition.
  • Cache aside pattern without stampede protection.
  • Check-then-act on database records without SELECT FOR UPDATE.
  • Assuming single-threaded PHP is race-condition-free.

Code Examples

✗ Vulnerable
// Race condition — read/increment/write without lock:
$count = (int)file_get_contents('counter.txt');
$count++;
file_put_contents('counter.txt', $count);
// Two simultaneous requests both read 5, both write 6
✓ Fixed
// File lock prevents race:
$fp = fopen('counter.txt', 'c+');
if (flock($fp, LOCK_EX)) {
    $count = (int)stream_get_contents($fp);
    $count++;
    ftruncate($fp, 0); rewind($fp);
    fwrite($fp, $count);
    flock($fp, LOCK_UN);
}
fclose($fp);

// Better: use atomic DB increment:
$pdo->exec('UPDATE counters SET value = value + 1 WHERE id = 1');

Added 23 Mar 2026
Views 32
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 3 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Perplexity 9 Amazonbot 7 Unknown AI 3 Ahrefs 2 Google 1 SEMrush 1
crawler 22 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Use flock() for file operations. Use DB atomic increments (UPDATE SET col = col + 1). Use SELECT FOR UPDATE for read-modify-write DB patterns. Use Redis INCR for counters.
📦 Applies To
web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
file_get_contents.*file_put_contents|read.*increment.*write
Auto-detectable: ✗ No semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Function Tests: Update
CWE-362 CWE-367

✓ schema.org compliant