Imagine two people sending files to one printer. If the printer alternates between their files line by line, neither gets the intended result. Synchronization coordinates tasks so one can finish using the printer before another takes its turn. It also makes a task wait when its work depends on another task finishing first. section 8.3 section 2.8
This matters especially for threads: they share an address space, so one thread can read data another has changed. A critical section is code that multiple tasks could execute while accessing a shared resource. Without coordination, the result may depend on which task reaches that code first—a race condition. The operating system cannot infer every rule the application needs, such as keeping one print job together. section 4.7 section 8.3 section 8.7
Several mechanisms can protect a shared resource:
- An atomic operation cannot be observed by another thread in a partially completed state; it depends on hardware and runtime support. section 8.7
- A lock permits access to protected code or data only while a task owns it. A mutex provides mutually exclusive access; a semaphore can permit several tasks at once. section 8.7
The dining philosophers
Five philosophers share chopsticks with their neighbors, and each needs two to eat. Treat each chopstick as a mutex: take the left, take the right, eat, then release both. The rules protect access, but they also reveal a danger: if tasks acquire locks that never become available, progress can stop. A lock is not a substitute for a sound acquisition-and-release plan. section 9.1
Synchronization can also order communication rather than protect memory. In a synchronous exchange, both parties must be ready and wait for the exchange to finish—like a phone conversation. With asynchronous messaging, a sender can move on and handle the reply later—more like texting. section 11.7
Use synchronization when tasks must share a resource or respect a dependency, but do not add it by default. Locks introduce delays and can limit scalability. Where possible, divide work into independent tasks or avoid shared memory through message passing; less coordination can mean simpler, faster-running programs. section 2.8 section 9.10










