Master Python Thread Synchronization: 10 Practical Code Scenarios
This article explains Python's thread‑synchronization primitives—including locks, RLocks, conditions, events, semaphores, read‑write locks, queues, thread pools, the GIL, and high‑level concurrency libraries—while providing ten ready‑to‑run code examples for each mechanism.
1. Lock
A basic synchronization primitive that protects shared resources from concurrent access. Implemented with threading.Lock.
import threading
lock = threading.Lock()
def my_function():
lock.acquire()
# access shared resource
# ...
lock.release()2. Re‑entrant Lock (RLock)
A special lock that can be acquired multiple times by the same thread, preventing deadlock in recursive scenarios. Implemented with threading.RLock.
import threading
lock = threading.RLock()
def my_function():
with lock:
# access shared resource
# ...3. Condition Variable
Enables threads to wait for certain conditions before proceeding and to notify waiting threads when those conditions are met. Implemented with threading.Condition.
import threading
condition = threading.Condition()
def consumer():
with condition:
while not condition_fullfilled():
condition.wait()
# perform consumption
def producer():
with condition:
# produce data
condition.notify()4. Event
A simple flag that threads can wait on until another thread sets it. Implemented with threading.Event.
import threading
event = threading.Event()
def consumer():
event.wait()
# perform consumption
def producer():
# produce data
event.set()5. Semaphore
A counting semaphore that limits the number of threads that can access a resource simultaneously. Implemented with threading.Semaphore.
import threading
semaphore = threading.Semaphore(3) # allow up to 3 concurrent threads
def my_function():
with semaphore:
# access shared resource
# ...6. Read‑Write Lock
Allows multiple readers or a single writer at a time. Python has no built‑in read‑write lock, but it can be built using RLock and Condition.
import threading
lock = threading.RLock()
condition = threading.Condition(lock)
readers = 0
def reader():
global readers
with lock:
while writers > 0:
condition.wait()
readers += 1
# perform read operation
with lock:
readers -= 1
if readers == 0:
condition.notify_all()
def writer():
with lock:
while readers > 0:
condition.wait()
# perform write operation
with lock:
condition.notify_all()7. Queue
A thread‑safe data structure for passing data between producer and consumer threads. Provided by the queue module.
import queue
q = queue.Queue()
def producer():
# produce data
q.put(data)
def consumer():
data = q.get()
# consume data8. Thread Pool
Manages a pool of reusable threads to reduce the overhead of thread creation. Implemented with concurrent.futures.ThreadPoolExecutor.
import concurrent.futures
def my_function(item):
# perform some operation on item
return result
with concurrent.futures.ThreadPoolExecutor() as executor:
results = executor.map(my_function, data)9. Global Interpreter Lock (GIL)
The GIL ensures that only one thread executes Python bytecode at a time, which limits true parallelism on multi‑core CPUs but still allows concurrency for I/O‑bound tasks and C extensions.
10. High‑Level Concurrency Libraries
Beyond the built‑in threading primitives, Python offers libraries such as asyncio, multiprocessing, and the enhanced threading module to simplify concurrent programming.
Choosing the appropriate synchronization mechanism and applying it correctly is essential for building efficient and reliable multithreaded applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
