class LightswitchObj: def __init__(self): self.count = 0 self.mutex = Semaphore(1) def lock(self, semaphore): self.mutex.wait() self.count += 1 if self.count == 1: semaphore.wait() self.mutex.signal() def unlock(self, semaphore): self.mutex.wait() self.count -= 1 if self.count == 0: semaphore.signal() self.mutex.signal()
# turnstile # desired: (all rendezvous) < (all critical points) from sync import Thread, Semaphore, watcher N_THREADS = 10 count = 0 mutex = Semaphore(1) turnstile = Semaphore(0) def child(i): global count print(str(i) + "rendezvous") mutex.wait() count += 1 mutex.signal() if count == N_THREADS: turnstile.signal() turnstile.wait() turnstile.signal() print(str(i) + "critical point") # note that the turnstile is _not_ ready to go again: it has a value of 1 watcher() [Thread(child, i) for i in range(N_THREADS)]
# readers writers # desired: n readers can all simultaneously read a value but only 1 writer can write # no readers can be reading while writing is happening # note that there's a tendency for starvation to occur unless you tune the sleeps properly from sync import Thread, Semaphore, watcher import time, random N_READERS = 5 N_WRITERS = 5 value = 0 readers = 0 mutex = Semaphore(1) roomEmpty = Semaphore(1) def writer(i): global value while True: time.sleep(random.random()) roomEmpty.wait() value = random.randint(0,5) print("Writer %d is writing %d" % (i, value)) time.sleep(random.random() * 3) roomEmpty.signal() def reader(i): global value global readers while True:
# barrier # desired: (all rendezvous) < (all critical point) # suboptimal because the last task probably is the lowest-priority task, so this involves a lot of context switches from sync import Thread, Semaphore, watcher N_THREADS = 10 count = 0 mutex = Semaphore(1) barrier = Semaphore(0) def child(i): global count print(str(i) + "rendezvous") mutex.wait() count += 1 if count == N_THREADS: for j in range(N_THREADS): barrier.signal() mutex.signal() barrier.wait() print(str(i) + "critical point") # note that the barrier is ready to go again watcher() [Thread(child, i) for i in range(N_THREADS)]
# multiplex # desired: up to NUM_SIMULTANEOUS "critical point" at once from sync import Thread, Semaphore, watcher NUM_SIMULTANEOUS = 3 multiplex = Semaphore(NUM_SIMULTANEOUS) def child(i): print(str(i) + "a") multiplex.wait() print(str(i) + "critical point") multiplex.signal() print(str(i) + "c") watcher() [Thread(child, i) for i in range(10)]
# producer-consumer with fixed buffer size # desired: producer sends an event every so often # if nothing is in the queue consumer should wait # block on the producer side if we're out of buffer spaces from sync import Thread, Semaphore, watcher import time, random from collections import deque BUFFER_SIZE = 3 mutex = Semaphore(1) items = Semaphore(0) spaces = Semaphore(BUFFER_SIZE) buffer = deque() t0 = time.time() class Event: def __init__(self, x): self.x = x def producer(): global buffer i = 0 while True: time.sleep(1) event = Event(i)
# cowboys # desired: group of cowboys eat dinner from a large pot with M servings of chili # cowboy wants to eat, he helps himself from pot # if pot empty, cowboy wakes up the cook then waits until cook refills the pot from sync import Thread, Semaphore, watcher import time, random N_COWBOYS = 10 M = 15 t0 = time.time() servings = 0 mutex = Semaphore(1) emptyPot = Semaphore(0) fullPot = Semaphore(0) def cowboy(i): global servings while True: mutex.wait() if servings == 0: print("[%f] Cowboy %d is asking cook to refill pot" % (time.time() - t0, i)) emptyPot.signal() fullPot.wait() servings = M servings -= 1 time.sleep(random.random()) # it takes up to 1s to take a serving print("[%f] Cowboy %d took a serving with %d servings left" % (time.time() - t0, i, servings))
# desired: "b" then "a" from sync import Thread, Semaphore, watcher sem = Semaphore(0) def child1(): sem.wait() print("child a") def child2(): print("child b") sem.signal() watcher() threada = Thread(child1) threadb = Thread(child2)
# producer-consumer # desired: producer sends an event every so often # if nothing is in the queue consumer should wait from sync import Thread, Semaphore, watcher import time, random from collections import deque mutex = Semaphore(1) items = Semaphore(0) buffer = deque() class Event: def __init__(self, x): self.x = x def producer(): global buffer i = 0 while True: time.sleep(random.random() * 5) event = Event(i) print("Producing event %d!" % event.x) mutex.wait() buffer.append(event) mutex.signal() items.signal() i += 1 def consumer():
# readers writers using lightswitches avoiding starvation # desired: n readers can all simultaneously read a value but only 1 writer can write # no readers can be reading while writing is happening from sync import Thread, Semaphore, watcher from LightswitchObj import LightswitchObj import time, random N_READERS = 5 N_WRITERS = 5 value = 0 lightswitch = LightswitchObj() roomEmpty = Semaphore(1) turnstile = Semaphore(1) def writer(i): global value while True: time.sleep(random.random()) turnstile.wait() roomEmpty.wait() value = random.randint(0, 5) print("Writer %d is writing %d" % (i, value)) time.sleep(random.random() * 3) turnstile.signal() roomEmpty.signal()
# rendezvous # desired: (a1 and b1) < (a2 and b2) from sync import Thread, Semaphore, watcher sem1 = Semaphore(0) sem2 = Semaphore(0) def child1(): print("a1") sem1.signal() sem2.wait() print("a2") def child2(): print("b1") sem2.signal() sem1.wait() print("b2") watcher() threada = Thread(child1) threadb = Thread(child2)
def __init__(self, n): self.N_THREADS = n self.count = 0 self.mutex = Semaphore(1) self.turnstile = Semaphore(0) self.turnstile2 = Semaphore(0)
class Barrier: def __init__(self, n): self.N_THREADS = n self.count = 0 self.mutex = Semaphore(1) self.turnstile = Semaphore(0) self.turnstile2 = Semaphore(0) def phase1(self): self.mutex.wait() self.count += 1 if self.count == self.N_THREADS: for j in range(self.N_THREADS): self.turnstile.signal() self.mutex.signal() self.turnstile.wait() def phase2(self): self.mutex.wait() self.count -= 1 if self.count == 0: for j in range(self.N_THREADS): self.turnstile2.signal() self.mutex.signal() self.turnstile2.wait() def wait(self): self.phase1() self.phase2()
# dining philosophers # desired: n philosophers, each of whom require left and right chopsticks, must eat # this induces deadlock from __future__ import print_function from sync import Thread, Semaphore, watcher import time, random N_PHILOSOPHERS = 5 chopsticks = [Semaphore(1) for i in range(N_PHILOSOPHERS)] # chopsticks_used is just for illustration purposes and isn't part of the solution chopsticks_used = [False for i in range(N_PHILOSOPHERS)] mutex_chopsticks_used = Semaphore(1) def print_chopstick(chopstick): if chopstick: return "X" else: return "O" def left(i): return i def right(i): return (i + 1) % N_PHILOSOPHERS
# readers writers using lightswitches # desired: n readers can all simultaneously read a value but only 1 writer can write # no readers can be reading while writing is happening # note that there's a tendency for starvation to occur unless you tune the sleeps properly from sync import Thread, Semaphore, watcher from LightswitchObj import LightswitchObj import time, random N_READERS = 5 N_WRITERS = 5 value = 0 lightswitch = LightswitchObj() roomEmpty = Semaphore(1) def writer(i): global value while True: time.sleep(random.random()) roomEmpty.wait() value = random.randint(0, 5) print("Writer %d is writing %d" % (i, value)) time.sleep(random.random() * 3) roomEmpty.signal() def reader(i): global value
def __init__(self): self.count = 0 self.mutex = Semaphore(1)
# mutex # desired: count always 2 at end # note that because python, you don't really need a mutex because python only simulates multiple threads # however this is just to show the concept from sync import Thread, Semaphore, watcher mutex = Semaphore(1) count = 0 def child1(): global count mutex.wait() print("a1") count += 1 mutex.signal() def child2(): global count mutex.wait() print("b1") count += 1 mutex.signal() watcher()