Synchronization

Operating Systems ยท 10 interview questions

When threads share memory, interleaving can corrupt state: a race condition is when the outcome depends on scheduling. The region of code that must not be entered by two threads at once is the critical section, and a correct solution needs mutual exclusion, progress, and bounded waiting.

A mutex provides mutual exclusion and has an owner โ€” the thread that locked it is the one that must unlock it. A semaphore is a counter with wait and signal operations and has no owner, so any thread may signal it. A binary semaphore looks like a mutex but is not one, precisely because of that ownership difference: it can be used for signalling between threads, which a mutex cannot.

That distinction is the single most common thing candidates get wrong here, and it's the reason priority inheritance is possible for mutexes but not for semaphores โ€” you can only boost a holder you can identify.

Synchronization interview questions

What is a race condition?
When the result depends on the relative timing of threads โ€” two threads reading, incrementing and writing the same counter can lose an update because the read-modify-write isn't atomic.
What three properties must a critical-section solution have?
Mutual exclusion (at most one thread inside), progress (if nobody is inside, someone waiting gets in, and the decision can't be postponed indefinitely), and bounded waiting (a limit on how many others enter first).
What's the real difference between a mutex and a binary semaphore?
Ownership. A mutex is owned by the thread that locked it and only that thread can unlock it. A semaphore has no owner, so any thread can signal it โ€” which makes it usable for signalling between threads, and makes priority inheritance impossible.
Why they ask: The most commonly fumbled question in this whole topic. 'A mutex is a binary semaphore' is wrong.
What is a counting semaphore for?
Controlling access to a pool of N interchangeable resources. The counter starts at N; wait decrements and blocks at zero; signal increments and wakes a waiter.
When is a spinlock the right choice?
On a multiprocessor, when the critical section is very short โ€” shorter than the cost of blocking and rescheduling. On a uniprocessor it's counterproductive: the spinner holds the CPU the lock holder needs.
What is a condition variable, and why is it always paired with a mutex?
It lets a thread wait until a predicate becomes true. It's paired with a mutex because the predicate depends on shared state: waiting atomically releases the mutex and sleeps, so no signal can be missed in the gap between checking and waiting.
Why must a condition-variable wait sit in a while loop rather than an if?
Because a wait can return without the predicate holding โ€” a spurious wakeup, or another thread consuming the condition first. Re-checking in a loop is the only correct pattern.
Why they ask: A precise, practical detail that shows real concurrency experience.
What does the producer-consumer problem require?
A bounded buffer with producers blocking when full and consumers when empty. The standard solution uses two counting semaphores for empty and full slots plus a mutex for buffer access.
What is the readers-writers problem?
Many readers may share access, but a writer needs exclusivity. The difficulty is fairness: reader-preference can starve writers indefinitely, writer-preference can starve readers, so real implementations compromise.
Why do locks need hardware support?
Because a lock check and set must be indivisible. Instructions like test-and-set or compare-and-swap do both atomically; without them, two threads could both observe the lock free and both take it.

You'll forget most of this by next week

That's not a discipline problem, it's how memory works. In the app these come back on an expanding schedule โ€” right before you'd lose them.

Start free for 7 days