How to Use Semaphore in Python for Thread Control
In Python, use
threading.Semaphore to limit the number of threads accessing a resource simultaneously. Create a semaphore with a count, then use acquire() to enter and release() to exit the critical section.Syntax
The threading.Semaphore class controls access to a shared resource by multiple threads. You create it with an initial count that sets how many threads can access the resource at once.
semaphore = threading.Semaphore(value): Creates a semaphore with a given count.semaphore.acquire(): Decreases the count by one, blocking if count is zero until another thread releases.semaphore.release(): Increases the count by one, allowing other threads to acquire.
python
import threading # Create a semaphore allowing 3 threads at once semaphore = threading.Semaphore(3) # Acquire the semaphore (decrement count) semaphore.acquire() # Release the semaphore (increment count) semaphore.release()
Example
This example shows 5 threads trying to access a resource, but only 2 can enter at the same time because the semaphore count is 2. Each thread waits 2 seconds inside the critical section.
python
import threading import time def worker(semaphore, thread_id): print(f"Thread {thread_id} waiting to enter") semaphore.acquire() print(f"Thread {thread_id} entered") time.sleep(2) # Simulate work print(f"Thread {thread_id} leaving") semaphore.release() semaphore = threading.Semaphore(2) threads = [] for i in range(5): t = threading.Thread(target=worker, args=(semaphore, i+1)) threads.append(t) t.start() for t in threads: t.join()
Output
Thread 1 waiting to enter
Thread 2 waiting to enter
Thread 3 waiting to enter
Thread 4 waiting to enter
Thread 5 waiting to enter
Thread 1 entered
Thread 2 entered
Thread 1 leaving
Thread 3 entered
Thread 2 leaving
Thread 4 entered
Thread 3 leaving
Thread 5 entered
Thread 4 leaving
Thread 5 leaving
Common Pitfalls
Common mistakes when using semaphores include:
- Not releasing the semaphore after acquiring it, causing deadlocks.
- Using a semaphore count that is too high or too low for the resource limits.
- Forgetting that
acquire()blocks the thread if the count is zero, which can freeze your program if not handled.
Always use try-finally or context managers to ensure release() is called.
python
import threading semaphore = threading.Semaphore(1) # Wrong way: forgetting to release semaphore.acquire() # ... do work # semaphore.release() # Missing release causes deadlock # Right way: always release semaphore.acquire() try: # ... do work pass finally: semaphore.release()
Quick Reference
Remember these key points when using threading.Semaphore:
- Initialize with the max number of threads allowed.
- Use
acquire()before entering the critical section. - Use
release()after leaving to free the slot. - Use
try-finallyto avoid deadlocks.
Key Takeaways
Use threading.Semaphore to limit concurrent thread access to resources.
Always pair acquire() with release() to avoid deadlocks.
Semaphore count controls how many threads can enter simultaneously.
Use try-finally blocks to ensure release() is called even if errors occur.
Semaphore.acquire() blocks if no slots are available, so plan accordingly.