Synchronization PrimitivesSemaphoresHard⏱️ ~3 min

Semaphore Semantics and Subtleties

Key Insight
Semaphores have subtle semantics that can trip up programmers. Understanding what is NOT guaranteed is as important as what is.

Things NOT Guaranteed

Semaphore Gotchas
No OwnershipAny thread can signaleven without wait()Accidental signalscause hard bugsNo FairnessWake order isimplementation-definedCould be FIFO, randomor priority-basedSignal Not LostUnlike cond vars,signals are storedCounter rememberspast signals

1. No Ownership

Unlike mutexes, semaphores have no concept of ownership. Any thread can signal any semaphore, even if it never waited. This flexibility is powerful but dangerous. Thread A can accidentally signal a semaphore that Thread B was supposed to signal.

2. No Fairness Guarantee

When multiple threads are blocked on a semaphore and signal() is called, which thread wakes up? The standard says nothing. It could be FIFO, could be random, could be priority based. Never assume a specific order.

3. Signals Are Never Lost

This is different from condition variables! If you signal a semaphore with no waiters, the count increases. A future wait() will succeed immediately. The signal is "stored" in the counter.

Summary: Semaphores are low-level primitives. They give you power but not safety. Consider higher-level abstractions when possible.
💡 Key Takeaways
No ownership: any thread can signal any semaphore. Unlike mutex which must be unlocked by the locker.
No fairness: order of waking blocked threads is undefined. Do not assume FIFO or priority ordering.
Signals are not lost: unlike condition variables, semaphore remembers signals. Safe to signal before wait.
Easy to over signal: calling signal() too many times creates phantom permits. Careful bookkeeping required.
Semaphores cannot detect bugs: they blindly count. A logic error in signal/wait pairing causes subtle corruption.
📌 Examples
1Over signaling bug: releasing a resource twice signals twice, allowing more threads than resources exist.
2No ownership pitfall: Thread A locks, Thread B unlocks. Works with semaphore (dangerous), fails with mutex (usually throws).
← Back to Semaphores Overview