Semaphore Based Resource Pools
A counting semaphore holds a number of permits. A thread calls acquire to take a permit, blocking if none are available, and calls release to return one. It is the natural tool for managing a pool of identical resources such as database connections, file handles, or worker slots.
To build a resource pool, initialize a semaphore with as many permits as there are resources. A thread that wants a resource acquires a permit, takes one resource from the pool, uses it, returns it, and releases the permit. The semaphore guarantees that at most that many threads ever hold a resource at once, so excess threads wait instead of overwhelming the pool.
Why a semaphore rather than a plain lock? A lock allows exactly one holder, while a counting semaphore allows up to N. This is exactly the bounded concurrency a connection pool needs.
Key cautions:
- Every acquire must be paired with a release, usually in a finally block, or permits leak and the pool slowly drains to zero
- Semaphores have no concept of ownership, so any thread can release, which is flexible but error prone
- A fair semaphore hands out permits in arrival order to prevent starvation, at a small throughput cost
A semaphore initialized with a single permit acts as a mutex, showing that a lock is just the limiting case of a counting semaphore with N equal to one.
Key idea
A counting semaphore caps how many threads can hold a pooled resource at once, and every acquire must be matched by a release or the pool leaks permits until it stalls.