Chapter 19. Concurrency
In the long run it is not advisable to write large concurrent programs in machine-oriented languages that permit unrestricted use of store locations and their addresses. There is just no way we will be able to make such programs reliable (even with the help of complicated hardware mechanisms).
Per Brinch Hansen (1977)
Patterns for communication are patterns for parallelism.
If your attitude toward concurrency has changed over the course of your career, you’re not alone. It’s a common story.
At first, writing concurrent code is easy and fun. The tools—threads, locks, queues, and so on—are a snap to pick up and use. There are a lot of pitfalls, it’s true, but fortunately you know what they all are, and you are careful not to make mistakes.
At some point, you have to debug someone else’s multithreaded code, and you’re forced to conclude that some people really should not be using these tools.
Then at some point you have to debug your own multithreaded code.
Experience inculcates a healthy skepticism, if not outright cynicism, toward all multithreaded code. This is helped along by the occasional article explaining in mind-numbing detail why some obviously correct multithreading idiom does not work at all. (It has to do with “the memory model.”) But you eventually find one approach to concurrency that you think you can realistically use without constantly making mistakes. You can shoehorn pretty much everything into that idiom, and (if you’re ...