/*:#localized(key: "WrappingUp")
 # Wrapping up

 Every bug in this chapter grows from one seed: shared mutable state, touched
 by concurrent work, with nothing coordinating the access. What makes a data
 race so dangerous is that it hides, so a passing test proves nothing but
 luck. The takeaways below are really one habit: learning to spot that shape
 by reading, and knowing how to shut it down.

 * A **data race** is concurrent access to shared mutable state with at least
 one writer; a **race condition** is any bug whose outcome depends on timing.
 * Races are **nondeterministic**: usually right, sometimes wrong, rarely
 reproducible. You catch them by *reading* for shared-and-mutated state, not
 by running; a green run only proves you got lucky this time.
 * `x += 1` and dictionary/array updates are **read-then-write** with a gap,
 not atomic. That gap is where corruption lives.
 * Fix by coordinating access: a **serial queue** (one at a time) or a
 **concurrent queue with `.barrier`** writes (readers-writers). All access to
 one piece of state must go through the *same* coordinator: hide it inside a
 type so callers can't bypass it.
 * A **deadlock** is a permanent circular wait. Never `sync` onto the queue
 you're already on, especially not `DispatchQueue.main.sync` from the main
 thread.
 * **Priority inversion** is a high-priority task blocked on a resource a
 low-priority task holds; keep critical sections short and don't mix wildly
 different QoS on one lock.

 ---
 
 ## Up next

 **[Operations](Operations.playgroundchapter/Overview)**: wrapping units of work as reusable objects you can
 name, configure, cancel, and chain, with `Operation` and `OperationQueue`.

 [Previous](@previous)  |  page 9 of 9
 */
