-
Notifications
You must be signed in to change notification settings - Fork 0
14 — Data Races and Thread Safety
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.
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.
Thread A ──▶ ┐
├──▶ [ counter ] ──▶ ??? (corrupted / undefined)
Thread B ──▶ ┘
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.
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.
GCD hands you the tools, not the safety net.
A garbled paper ticket is at least visibly wrong; a data race in memory can silently produce a plausible-looking but incorrect value.
Why doesn't the counter example above reliably print 1000?