Operating Systems

Synchronization

Coordinating threads that share state so the result could have been sequential.

Level: intermediate

What is it?

Synchronization provides ordering and coordination between concurrent activities. Common mechanisms include mutexes, semaphores, condition variables, atomics, barriers, and message passing. The right primitive depends on whether the requirement is exclusive access, notification, ordering, or a count of available resources.

Why does it matter?

Concurrency bugs are often timing-dependent. Synchronization protects invariants across interleavings and establishes when one thread's writes become visible to another, but careless synchronization can introduce deadlocks and contention.

Mental model

Treat synchronization as rules for shared state. A lock controls who can enter a critical section; a condition variable lets a thread sleep until a predicate may be true; an atomic operation updates a small value indivisibly.

How it works

  • Mutual exclusion prevents concurrent entry to a critical section, but does not by itself guarantee fairness.
  • Condition-variable waits should be inside a loop that checks the predicate because wake-ups can be spurious or another thread may consume the condition first.
  • Atomics are appropriate for specific operations and memory-ordering contracts, not as a universal replacement for locks.
  • Lock ordering and minimizing lock hold times help reduce deadlocks and contention.
  • Message passing can avoid shared mutable state but still needs protocol and backpressure design.

Steps

  • Two threads need to update a shared map.
  • Identify the invariant: insertions and lookups must observe a consistent structure.
  • Protect the compound update with a mutex or choose a concurrent data structure with an appropriate contract.
  • Test with stress runs and race detectors; a single successful run does not prove correctness.

Real-world usage

  • Implementing producer-consumer queues and shared counters.
  • Choosing between a mutex, atomic, semaphore, or condition variable.
  • Diagnosing flaky races and lock contention.

Common mistakes

  • Using a lock but updating some related state outside it.
  • Waiting on a condition once without rechecking the predicate.
  • Assuming volatile alone makes compound operations atomic or establishes full synchronization in every language.

Interview questions

What does a mutex guarantee?

It grants exclusive ownership of a protected region to one owner at a time; the program must still define the invariant and locking discipline.

When is a condition variable useful?

When a thread should sleep until a state predicate may become true, such as a queue becoming non-empty, instead of busy-waiting.

Why should condition-variable waits be in a loop?

Wake-ups can be spurious, and another thread may change the predicate before the awakened thread reacquires the lock.

Prerequisites

Related concepts

Continue learning

Browse the full computer science library