Concurrency Comparisons

Side-by-side trade-offs where neither column wins. The workload, the runtime and how much correctness risk you can carry decide — and each comparison ends with the verdict that follows from that, not from a preference.

Mutex vs semaphore

They look similar and are used for opposite purposes. A mutex protects an invariant; a semaphore limits a resource. Using one for the other's job is a recognizable code smell with a recognizable failure.

DimensionMutexSemaphore
What it expresses"Only one task may be inside this region""At most N tasks may be doing this at once"
What it protectsAn invariant over shared stateA limited resource or a rate of work
OwnershipOwned by the locker — usually only it may unlockNo ownership; any task may release a permit
CountOne, alwaysN, chosen by you
Typical scopeA few lines, no I/O insideA whole operation, including I/O
Signature failureDeadlock from a second lock taken insidePermit leaked on an error path — capacity silently drops to zero
ReentrancyNon-reentrant by default; re-locking self-deadlocksNot applicable — taking two permits is legitimate
Right question"What must stay true?""How many at once, and why that number?"
Use Mutex when
  • A multi-field update must never be observed half-done.
  • The region is short and contains no I/O.
  • The correct answer to "how many at once" is exactly one.
Use Semaphore when
  • Capping in-flight requests to a downstream service.
  • Bounding memory by bounding how many large buffers exist at once.
  • Gating access to a fixed pool of connections or file handles.
Verdict

If you are protecting correctness, it is a mutex. If you are protecting capacity, it is a semaphore. A semaphore with one permit used as a mutex loses ownership checks and gains a way to be released by the wrong task.