ConcurrencyverifiedVerified

Semaphore

Control access to a finite pool of resources by maintaining a counter that threads atomically increment (release) and decrement (acquire), blocking when the count reaches zero.

Coming Soon

errorWhat Problem Does the Semaphore Pattern Solve?

A mutex permits exactly one thread into a critical section, but many resources exist in limited quantities greater than one — a database connection pool of ten, a rate limit of five concurrent API calls, or three available GPU slots. Using one mutex per resource instance is unwieldy and doesn't naturally express the pool abstraction.

check_circleHow the Semaphore Pattern Works

Initialise a semaphore with a count equal to the number of available resource units. Each acquire decrements the count; if it would go below zero, the calling thread blocks. Each release increments the count, waking a blocked thread if any are waiting. This elegantly generalises the mutex (a semaphore initialised to 1) to arbitrary resource counts.

Semaphore Pattern Architecture

hourglass_empty

Rendering diagram...

Implementation by Language

lightbulb

Semaphore Pattern in the Real World

Imagine a car park with exactly three spaces. A ticket machine at the entrance (the semaphore) issues a ticket only if spaces remain, lifting the barrier; arriving drivers with no ticket available must wait. When a car exits, the machine automatically increments its counter and releases the next waiting driver — the car park never exceeds capacity.

Frequently Asked Questions

helpWhen should I use a Semaphore instead of a rate limiter?

Use a Semaphore to limit concurrent access (max N operations running simultaneously). Use a rate limiter to limit throughput over time (max N operations per second). A Semaphore doesn't care about time — it controls how many operations run at once, not how fast they start.

helpWhat happens if a Semaphore is never released?

The semaphore's count is permanently decremented, reducing the available permits. If all permits are leaked, the semaphore deadlocks — no new operations can acquire a permit. Always release in a finally block (try/finally) to prevent leaks, even when exceptions occur.