Everything that made this part hard fits inside five lines of code, where Part Iβs difficulties all grew with something: a bigger space, a longer table, more processes.
Why this matters
The professorβs reassurance is a technical claim rather than a kindness. Early published work in this area contained mistakes, and it was written by the very people inventing the field β so the difficulty belongs to the problem rather than to the reader.The concurrency arc closes as the others did β with the professor, the student, and an aching head.
The studentβs answer, itemized (click each row β it notes where the belief was earned):
| the belief | |
|---|---|
| 1 | Threads share everything β and that's the problem |
| 2 | A lock is built, not given |
| 3 | Add locks carefully β one big lock first |
| 4 | Condition variables let a thread sleep until state changes |
| 5 | One primitive can be both lock and CV |
| 6 | Concurrency bugs come in patterns |
| 7 | Threads aren't the only way |
| 8 | The best concurrency is the concurrency you avoid |
The Professorβs Three Rules of Concurrency
1. Keep it simple. Avoid complex thread interactions; use well-known, tried-and-true paradigms β simple locking lock A variable holding one of two states β available (free) or acquired (held by exactly one thread, the owner) β with lock() not returning until the caller holds it, and unlock() freeing it. Programmers bracket critical sections with them, making the section execute as if atomic. defined in ch. 28 β open in glossary , a producer/consumer producer/consumer problem Dijkstra's canonical synchronization problem (a.k.a. the bounded-buffer problem): one or more producer threads place items into a shared bounded buffer while one or more consumers remove them. Correct solutions need mutual exclusion on the buffer plus making producers wait when it is full and consumers wait when it is empty β a lock plus two condition variables (empty and fill). defined in ch. 30 β open in glossary queue.2. Use concurrency only when absolutely needed. Avoid it if you can β there is nothing worse than premature optimization.
3. If you truly need parallelism, seek simplified forms. MapReduce lets you write parallel data analysis with no locks, condition variables, or other nasty things at all.
If you remember only three things
-
The question the professor calls the real one is never actually answered. βIf concurrent code is so hard to get right, how are we supposed to write it correctly?β earns three rules for writing less of it and an instruction to practise β there is no method here, only discipline.
-
The advice at the end is to practise rather than to study. Ten thousand hours, read more and write more; what you have just finished is called the barest introduction by the professor who taught it.
-
The one tool named works by removal. MapReduce hands you parallelism with none of the machinery this part spent ten chapters building β the concurrency still happens, somebody else wrote it once, and the programmer never meets it.
Next: Part III β Persistence
We virtualized one CPU into many, one memory into many address spaces, and made many threads cooperate without stepping on each other. The final piece: making data survive β I/O devices, spinning disks and SSDs, RAID, file systems, journaling, and the long fight to keep bits safe across crashes and time. The third easy piece begins.Check yourself: the concurrency wrap-up
1.What is the Professor's FIRST rule for writing correct concurrent code?
2.What is the Professor's second rule?
3.The Professor's third rule points to MapReduce as an example of what?
4.Recapping the Part: what fundamentally causes a race condition (chapter 26)?
5.Recap: why does the producer/consumer solution need TWO condition variables (chapter 30)?