Semaphore — Explained with Examples
A semaphore is a signaling mechanism that controls access to a shared resource by multiple threads using a counter-based permit system.
Semaphores maintain an internal counter. Counting semaphores allow up to N threads to access a resource concurrently (like a connection pool). Binary semaphores (counter 0 or 1) behave like a mutex but without ownership — any thread can signal (release), not just the one that waited (acquired). Dijkstra introduced semaphores as P (proberen = acquire/decrement) and V (verhogen = release/increment) operations.
Think of a semaphore like a parking lot with a capacity counter. A guard (semaphore) counts available spots. When a car enters, the count decreases. When a car leaves, the count increases. If the lot is full, cars wait at the entrance until a spot opens up. Unlike a mutex (one key for one bathroom), a semaphore allows multiple concurrent users up to a limit.
Semaphores are used for resource pools (database connections, thread pools) and producer-consumer scenarios.
import threading
import time
class ConnectionPool:
def __init__(self, size):
self.semaphore = threading.Semaphore(size)
self.connections = [f"conn-{i}" for i in range(size)]
def acquire(self):
self.semaphore.acquire()
conn = self.connections.pop()
print(f"Acquired {conn}")
return conn
def release(self, conn):
self.connections.append(conn)
print(f"Released {conn}")
self.semaphore.release()
# Pool of 2 connections, 5 threads competing
pool = ConnectionPool(2)
def worker(n):
conn = pool.acquire()
time.sleep(0.5) # Use connection
pool.release(conn)
threads = [threading.Thread(target=worker, args=(i,)) for i in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()Binary semaphores differ from mutexes: semaphores have no ownership concept, making them suitable for signaling between threads but dangerous for protecting critical sections.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro