Producer / Consumer and Locks
Mid-tier drills on bounded buffers, mutexes, semaphores, and deadlock detection. Code stems in Python and JavaScript; one trace involves the four conditions for deadlock.
1,174 views
20
Implement a bounded-buffer producer / consumer with a Python threading.Condition. The buffer has capacity 4. Producer waits when full; consumer waits when empty.
Examples
Example 1:
Input: BoundedBuffer(capacity = 4); producer thread calls put four times then a fifth time
Output: the first four puts succeed; the fifth blocks until a consumer's get notifies
Explanation: Use a single Condition guarding both 'not full' and 'not empty'. put waits while len(buf) == capacity in a while loop (never if, to handle spurious wake-ups), appends, then notify_all so a sleeping consumer can re-check.import threading
from collections import deque
class BoundedBuffer:
def __init__(self, capacity=4):
# TODO: store capacity, a deque, and a Condition
pass
def put(self, item):
# TODO: wait while full, then append and notify
pass
def get(self):
# TODO: wait while empty, then popleft and notify
passWhat four conditions must all hold simultaneously for deadlock to be possible (Coffman conditions)? Name each one and give a one-sentence example.
Fix the deadlock below by reordering lock acquisition. State which Coffman condition the fix breaks.
Examples
Example 1:
Input: t1 takes lockA then lockB; t2 takes lockB then lockA
Output (buggy version): deadlock when t1 holds A waiting B while t2 holds B waiting A
Output (fixed version): both threads acquire lockA first, then lockB, breaking the cycle in the wait-for graph
Explanation: A consistent global lock order eliminates the circular wait Coffman condition. The other three conditions (mutual exclusion, hold-and-wait, no preemption) still hold; only circular wait is broken.import threading
lockA = threading.Lock()
lockB = threading.Lock()
def t1():
with lockA:
with lockB:
pass
def t2():
with lockB:
with lockA:
passUse a threading.Semaphore(3) to cap concurrent downloads to 3. Sketch the wrapper. Why pick a semaphore over a Lock?
JavaScript is single-threaded, so why might you still need a mutex-like abstraction in async JS? Sketch a tiny AsyncMutex using a chained promise.
