Discusses the things you need to know to program threads in the real world. This article assumes you understand the language-level support for threads and focuses on the legion of problems that arise when you try to use these language features.
Discussion of two more architectural solutions to threading problems: a synchronous dispatcher (or 'reactor') and an asynchronous dispatcher (or 'active object').
A condition variable adds to wait the ability to not wait when the condition you're waiting for has already taken place; and a counting semaphore lets you control a pool of resources without sucking up machine cycles in polling loops.
Looks at how and why you might want to roll your own exclusion semaphores, and presents a lock manager that will help you safely acquire multiple semaphores.