Synchronization PatternsCounting SemaphoresHard⏱️ ~2 min

Counting Semaphores vs Other Primitives

Comparison Guide
Counting semaphores, mutexes, and condition variables overlap in capability but differ in semantics. Choose the right tool.

Semaphore vs Mutex

Mutex: Owned by a thread. Only the owner can unlock. Used for critical sections.

Semaphore: No ownership. Any thread can signal. Used for signaling and resource counting.

A semaphore CAN be used as a mutex (initialize to 1), but a mutex CANNOT count resources.

Semaphore vs Condition Variable

Semaphore: Remembers signals. Signal before wait? Wait succeeds. Stateful.

Condition Variable: Forgets signals. Signal before wait? Signal lost. Stateless.

Semaphores count events. Condition variables coordinate on conditions.

When to Use Which
Counting SemaphoreResource poolsSignalingBounded buffersMutexCritical sectionsData protectionSingle ownershipCondition VariableComplex conditionsState-based waitingMultiple predicates

Implementation Flexibility

You can implement a semaphore using mutex + condition variable + counter. You can implement a mutex using a binary semaphore. But they express different intentions. Use the one that matches your mental model.

Decision Heuristic

Protecting data? Use mutex. Counting resources? Use counting semaphore. Waiting for a condition to become true? Use condition variable with while loop.

Best Practice: Match the primitive to the problem. Mutexes for exclusion, semaphores for permits, condition variables for conditions. Using the wrong one makes code confusing.
💡 Key Takeaways
Mutex has ownership (only owner unlocks). Semaphore has no ownership (anyone can signal).
Semaphore remembers signals (stateful). Condition variable forgets (stateless, signal lost if no waiter).
Semaphore = resource counting. Mutex = critical section. Condition variable = wait-for-condition.
Semaphore can emulate mutex (N=1). Cannot easily emulate complex condition waiting.
Choose based on intent: protecting data (mutex), counting permits (semaphore), awaiting conditions (condvar).
📌 Examples
1Thread pool: use counting semaphore to track available worker threads. Natural fit for resource counting.
2Shared counter: use mutex to protect read-modify-write. Ownership ensures unlock by holder.
3Producer-consumer: can use semaphores (bounded buffer) or condvar (queue not empty/full conditions).
← Back to Counting Semaphores Overview