ConcurrencyIntermediate

Mutex vs semaphore

“What is the difference between a mutex and a semaphore? Is a binary semaphore the same thing as a mutex? When would you use each?”

What this tests

  • Ownership as the defining property of a mutex
  • A semaphore as a counter for signalling and resource pools
  • Why a binary semaphore is not a mutex
  • Implementation: futex fast path, spinning vs sleeping, and contention symptoms

Answers by level

Read the beginner answer first and notice what is missing.

A mutex protects a critical section and has an owner: the thread that locked it is the only one allowed to unlock it. That rule enables things a counter cannot: recursive locking, error checking (unlock by a non-owner is a bug the library can report), and priority inheritance — the kernel knows who holds it and can boost that thread when a higher-priority thread waits (Mutexes).

A semaphore is a counter with two operations: wait (decrement, block if zero) and signal (increment, wake a waiter). It has no owner — any thread, or an interrupt handler, may signal. That makes it a signalling primitive: a producer signals "one item is available", a consumer waits; N permits bound how many threads may use a pool of N connections at once (Semaphores and Condition Variables).

So a binary semaphore is *not* a mutex. It can be released by a thread that never acquired it — which is a feature when thread A hands a resource to thread B, or an ISR wakes a task — and a liability when used as a lock, because nothing stops the wrong thread from "unlocking", and there is no priority inheritance. For plain mutual exclusion use a mutex; for "wait until someone tells me" use a semaphore or, in most user-space code, a condition variable paired with a mutex; for "at most N concurrently" use a counting semaphore.

Both cost the same when uncontended and differ under contention only in what they express. The failure modes differ too: mutexes deadlock through ordering; semaphores leak permits (a path that returns without signalling) so the pool slowly shrinks until everyone waits forever.

Green flags · Red flags

Strong green flag · Says a binary semaphore is not a mutex because of ownership, and gives the ISR / hand-off use case.
Green flags
  • Names ownership as the difference
  • Explains what ownership enables (priority inheritance, error checking)
  • Describes the semaphore as signalling and pooling, releasable by non-acquirers
  • Mentions condition variables as the usual signalling tool with a mutex
  • Knows the futex fast path and what contention costs
Red flags
  • "Binary semaphore = mutex"
  • Cannot say when a non-owner releasing is desirable
  • Thinks uncontended locking is expensive

Follow-up questions

F1
A thread returns early on error inside a semaphore-guarded section. What happens over time?
F2
When is a spinlock the right choice?
F3
What does priority inheritance require that a semaphore lacks?

Scenario

A C++ service bounds outbound calls with a mutex-protected counter and a busy loop that sleeps 1 ms while the counter is at its limit. Replace the design with the right primitive and explain what changes in CPU use and latency.

Learn this topic