Skip to content

14 — Data Races and Thread Safety

rebeloper edited this page Jul 12, 2026 · 1 revision

🍽️ Intuition

Two chefs writing on the same order ticket at the same time — the final ticket is garbled, and nobody can predict what it actually says.

🧠 What It Means In Swift

A data race happens when two or more threads read/write the same mutable state concurrently without synchronization. GCD does not protect you from this automatically — submitting work to a concurrent queue that mutates shared state is a race waiting to happen.

📊 ASCII Diagram

Thread A ──▶ ┐
             ├──▶ [ counter ] ──▶ ??? (corrupted / undefined)
Thread B ──▶ ┘

💻 Tiny Swift Example

var counter = 0
let queue = DispatchQueue(label: "concurrent", attributes: .concurrent)

for _ in 0..<1000 {
    queue.async {
        counter += 1 // NOT thread-safe — final value is unpredictable
    }
}

👉 Run this and counter almost never ends up at 1000 — multiple threads read the same stale value, increment it, and write it back, silently clobbering each other's updates.

🔄 vs. Swift Concurrency

Sendable conformance checking (compile-time) and actor isolation catch most of these before you ever run the code, instead of surfacing as a flaky runtime bug.

🧸 Memory Sentence

GCD hands you the tools, not the safety net.

⚠️ Analogy Limit

A garbled paper ticket is at least visibly wrong; a data race in memory can silently produce a plausible-looking but incorrect value.

✅ Check Your Understanding

Why doesn't the counter example above reliably print 1000?

Clone this wiki locally