Semaphores (Permits)

A bouncer for your resources: "Only 3 threads allowed inside at once."

The idea

A Mutex is a lock with exactly 1 key. Only one thread can use a resource at a time. But what if you have a connection pool with exactly 3 Database Connections? You want to allow up to 3 threads to work simultaneously, and force the 4th thread to wait. A Semaphore is a concurrency primitive initialized with a number of "Permits". To do work, a thread must acquire a permit. When done, it releases the permit back to the Semaphore.

Step 1: A Semaphore is initialized with 2 permits (). Four threads want to do work.

How it works (Acquire / Release)

Semaphores are incredibly useful for Rate Limiting or throttling concurrent background workers. If you need to make 1,000 HTTP requests to an API, but the API bans you if you make more than 5 concurrent requests, you wrap your HTTP call in a Semaphore initialized with 5.

# Python example using asyncio.Semaphore

import asyncio

# A Bouncer that only allows 5 threads at once
api_bouncer = asyncio.Semaphore(5)

async def fetch_data(url):
    # The thread pauses here if 5 permits are already taken
    async with api_bouncer:
        # We got a permit! Do the work.
        response = await http.get(url)
        return response
        
    # The 'async with' block automatically releases the permit
    # back to the bouncer when it exits.

Cost

Semaphores are very efficient. However, they do not track which thread owns a permit. A thread can technically release a permit it never acquired, completely breaking the concurrency limit (a Mutex generally prevents this). Always use language constructs (like with in Python or try...finally) to guarantee releases.

Watch out for