Overview of Synchronization Primitives: Mutex, Semaphore, Condition Variable, Spinlock
Compare mutex, semaphore, condition variable, and spinlock — when to use each — with OS interview questions answered.
Expected Interview Answer
Synchronization primitives are the building blocks — mutexes, semaphores, condition variables, and spinlocks — that operating systems and languages provide to safely coordinate access to shared data among concurrent threads, each suited to a different coordination pattern rather than being interchangeable.
A mutex provides mutual exclusion with ownership, letting only the locking thread unlock it, and is the default choice for protecting a single critical section. A semaphore is an unowned counter suited to rationing a pool of N interchangeable resources or signaling between threads regardless of who last touched it. A condition variable is not a lock by itself but a waiting mechanism used alongside a mutex, letting a thread sleep until another thread signals that some specific condition has become true, avoiding busy-wait polling for state changes like 'queue is no longer empty.' A spinlock busy-waits instead of sleeping, trading CPU cycles for avoiding context-switch overhead, and is only appropriate for very short critical sections on multiprocessor systems, most commonly deep inside kernel code where sleeping is not even allowed. Choosing correctly among these means matching the coordination pattern — exclusive single-resource access, counted pooling, event notification, or ultra-short critical sections — to the primitive designed for it, since misapplying one (like using a spinlock for a long wait) actively hurts performance.
- Gives a mental map for choosing the right primitive for each coordination pattern
- Clarifies that condition variables solve waiting-for-a-condition, not exclusion
- Explains when spinning (spinlock) beats sleeping and vice versa
- Prevents common interview mistakes of treating all primitives as interchangeable
AI Mentor Explanation
Synchronization primitives are like different tools a ground uses to manage access: a mutex is a single net key only the checking-out player can return, a semaphore is a rack of five practice bats anyone can take or return, a condition variable is a whistle a coach blows only once the rain has actually stopped so waiting players know to resume, and a spinlock is a player jogging in place for two seconds waiting for a teammate to finish a quick handoff rather than sitting down. Each tool fits a different situation — exclusive access, pooled resources, waiting for an event, or a very brief wait — and using the wrong one, like jogging in place for an hour, wastes energy badly.
Step-by-Step Explanation
Step 1
Identify the coordination need
Determine whether you need exclusive single-resource access, a counted pool, waiting for a condition, or an ultra-short critical section.
Step 2
Match to a primitive
Mutex for exclusion, semaphore for pooling/signaling, condition variable for event waiting alongside a mutex, spinlock only for very brief kernel-level or multiprocessor waits.
Step 3
Apply correctly
Condition variables must always be used with an associated mutex and a while-loop re-check to guard against spurious wakeups.
Step 4
Verify the tradeoff
Confirm the choice matches expected wait duration — spin only when shorter than a context switch, otherwise block.
What Interviewer Expects
- A clear one-line distinction between all four primitives
- Correct pairing of condition variables with a mutex, not standalone use
- Knowing spinlocks are for very short, often kernel-level, critical sections
- Ability to pick the right primitive for a given scenario on the spot
Common Mistakes
- Treating a condition variable as a lock by itself
- Using a spinlock for long or uncertain-duration waits
- Forgetting to re-check the condition in a while loop after waking from a condition variable
- Believing mutex and semaphore are interchangeable in every case
Best Answer (HR Friendly)
“There are a handful of standard tools for coordinating threads: a mutex locks a single resource so only one thread touches it at a time, a semaphore is a counter for sharing a pool of several resources, a condition variable lets a thread sleep until told a specific event has happened, and a spinlock just loops very briefly waiting on something instead of sleeping. The interview skill is picking the right one for the situation — using a spinlock for anything longer than a tiny wait, for example, is a real performance mistake.”
Code Example
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
int queue_has_item = 0;
void consumer(void) {
pthread_mutex_lock(&lock);
while (!queue_has_item) /* re-check, guard spurious wakeups */
pthread_cond_wait(&ready_cond, &lock);
/* ... consume the item ... */
queue_has_item = 0;
pthread_mutex_unlock(&lock);
}
void producer(void) {
pthread_mutex_lock(&lock);
queue_has_item = 1;
pthread_cond_signal(&ready_cond); /* wake one waiting consumer */
pthread_mutex_unlock(&lock);
}Follow-up Questions
- Why must a condition variable wait always be inside a while loop, not an if?
- When would you choose a semaphore over a condition variable for signaling?
- Why are spinlocks common in kernel code but rare in user-level long waits?
- How does a reader-writer lock differ from a plain mutex?
MCQ Practice
1. What must a condition variable always be paired with?
A condition variable is used alongside a mutex that protects the shared state; the thread reacquires the mutex after being woken.
2. When is a spinlock the appropriate choice?
Spinlocks trade CPU cycles for avoiding context-switch overhead, which only pays off for very brief waits, and are used in contexts where blocking is disallowed.
3. Which primitive is best suited to rationing a pool of 5 interchangeable database connections?
A counting semaphore naturally models N interchangeable resources, letting up to 5 threads hold a connection concurrently.
Flash Cards
Mutex in one line? — Owned exclusive lock for a single critical section.
Semaphore in one line? — Unowned counter for rationing N interchangeable resources or signaling.
Condition variable in one line? — A wait mechanism paired with a mutex for sleeping until a specific condition becomes true.
Spinlock in one line? — A busy-waiting lock appropriate only for very short critical sections.