Locks and Synchronization

Python AdvancedConcurrencyFree Lesson

Advertisement

Introduction

Thread synchronization primitives like Lock, RLock, Semaphore, and Event coordinate access to shared resources in multithreaded programs.

Lock

import threading

class Counter:
    def __init__(self):
        self.value = 0
        self.lock = threading.Lock()
    
    def increment(self):
        with self.lock:
            self.value += 1
    
    def get(self):
        with self.lock:
            return self.value

counter = Counter()
threads = [threading.Thread(target=counter.increment) for _ in range(1000)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print(counter.get())  # 1000

RLock (Reentrant Lock)

import threading

lock = threading.RLock()

def outer():
    with lock:
        print("outer")

def inner():
    with lock  # Same lock can be acquired again
        print("inner")

def nested():
    with lock:
        outer()
        inner()

nested()  # Works with RLock, would deadlock with Lock

Semaphore

import threading
import time

# Limit to 3 concurrent connections
semaphore = threading.Semaphore(3)

def worker(n):
    with semaphore:
        print(f"Worker {n} started")
        time.sleep(1)
        print(f"Worker {n} finished")

threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
for t in threads:
    t.start()
for t in threads:
    t.join()

Event

import threading
import time

event = threading.Event()

def worker(n):
    print(f"Worker {n} waiting")
    event.wait()  # Block until set
    print(f"Worker {n} proceeding")

threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
for t in threads:
    t.start()

time.sleep(2)
event.set()  # Release all waiting threads

Condition

import threading

class BoundedBuffer:
    def __init__(self, size=5):
        self.buffer = []
        self.size = size
        self.lock = threading.Condition()
    
    def put(self, item):
        with self.lock:
            while len(self.buffer) >= self.size:
                self.lock.wait()
            self.buffer.append(item)
            self.lock.notify()
    
    def get(self):
        with self.lock:
            while not self.buffer:
                self.lock.wait()
            item = self.buffer.pop(0)
            self.lock.notify()
            return item

Practice Problems

  1. Implement thread-safe counter with Lock
  2. Use RLock for recursive operations
  3. Control concurrent access with Semaphore
  4. Coordinate threads with Event
  5. Implement producer-consumer with Condition

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement