Concurrency
Concurrency is what happens when the threads the operating-systems topic introduced stop merely taking turns on one core and start genuinely running at the exact same instant, and that single change opens up an entire category of bugs that simply cannot occur in code that only ever runs one instruction stream at a time. A race condition happens when two threads read and write the same shared memory without any coordination: if thread A reads a shared counter, thread B reads the same old value before A writes back, and then both write their own incremented result, one of the two increments is silently lost, even though each individual line of code looks perfectly correct in isolation — this is exactly the danger the operating-systems topic warned about when it said a bug in one thread can corrupt data another thread depends on. Synchronization is the fix: a lock (or mutex) lets only one thread touch a piece of shared data at a time, forcing every other thread that wants it to wait its turn, which restores correctness at the direct cost of some of concurrency's speed, the same tradeoff the databases topic's transactions already made for exactly the same reason. A deadlock is what happens when synchronization is used carelessly: if thread A holds lock 1 and waits for lock 2, while thread B holds lock 2 and waits for lock 1, neither thread can ever proceed, because each is waiting on a resource the other refuses to release — a cycle of waiting with no way out, the same circular-dependency shape the algorithms topic's graph coverage would flag as a cycle if the "waits for" relationships were drawn as a graph. Multicore computing sidesteps the scheduler's time-slicing illusion from the operating-systems topic entirely by giving each thread its own real, physical CPU core from the computer-architecture topic, so multiple instruction streams genuinely execute at the same instant rather than just appearing to. A GPU takes that idea to an extreme: instead of a handful of powerful, independent cores, a GPU packs thousands of small, simple cores that all execute the exact same instruction on different pieces of data simultaneously, which is a poor fit for a program full of branching decisions but an extremely good fit for the kind of uniform, repeated math — like running the identical calculation across millions of pixels or matrix entries — that later topics in this series, especially artificial intelligence, depend on almost entirely. None of this complexity is optional once a program needs to use more than one core at once; it is the price of real parallel speed, and the next topic, distributed systems, raises the exact same race-condition and coordination problems introduced here, except stretched across many separate machines connected only by the network the computer-networks topic already covered.