Synchronization: locks and the bounded buffer
When threads share data, the result of an operation can depend on how their steps interleave. That is a race condition. The code that touches shared data is a critical section, and mutual exclusion means only one thread at a time may be inside it. A lock (mutex) enforces this: a thread acquires the lock before the critical section and releases it afterwards.
Python
import queue
import threading
counter = 0
lock = threading.Lock()
def work():
global counter
for _ in range(10000):
with lock:
counter += 1
workers = [threading.Thread(target=work) for _ in range(4)]
for worker in workers:
worker.start()
for worker in workers:
worker.join()
buffer = queue.Queue(maxsize=2)
results = []
def producer():
for item in range(1, 6):
buffer.put(item)
buffer.put(None)
def consumer():
while True:
item = buffer.get()
if item is None:
break
results.append(item * item)
threads = [threading.Thread(target=producer), threading.Thread(target=consumer)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
print(results)
print(counter)