Once upon a time there was a special restaurant, The Kitchen Sync. It wasn’t famous for it’s food: it was famous for having a wider range of synchonization primitives than any other restaurant in town.
The restaurant only sat people in groups of 4. You’d show up and be placed in the entrance waiting room; once enough people were there, 4 at random (not necessarily a group who arrived together) would be picked to enter the restaraunt.
from threading import Barrier
= Barrier(4)
entrance
def arrive():
# stop waiting in groups of 4
entrance.wait() dine()
Drinks were self-serve, but there was only one drinks station. If you wanted a refill on your water you might get lucky and get there when no one else was there, or you might have to wait for someone else to finish at the station first.
from threading import Lock
= Lock()
drink_station
def get_drink():
with drink_station: # will wait here
refill_drink()return # sit back down
notify_all
Food was also self-serve single-station, but in addition it often ran out. You’d wait your turn in a queue to get access to the station, but when you got there there the dish you wanted might be empty. When that happened you’d go into the food waiing room. Eventually a server would add more food and notify everyone in the waiting room to get back into the queue to access the station again.
from threading import Condition
= Condition()
food_station
= {"bread":0, "salad":0, "fruit":0, "protein":0}
dishes
def get_food(dish):
with food_station: # will queue here
while dishes[dish] == 0:
# enter waiting room here
food_station.wait() # wait() also is where you re-queue when notified
-= 1
dishes[dish]
add_to_plate(dish)return # sit back down
def refill_food(dish, servings):
with food_station:
+= servings
dishes[dish] # reqeue waiting customers
food_station.notify_all() return # got back to kitchen
notify
When you finished your meal you’d wait in line at the register to pay, and after you paid you’d be given a desert. Deserts were made one at a time and if there weren’t enough deserts, after paying you’d be put in the desert waiting room. When a new desert was ready one person in the waiting room would called to get their desert, but sometimes they’d come back to the waiting room a moment later because someone else had arrived, paid, and taken that desert while they were leaving the waiting room.
from threading import Condition
= Condition()
register
= 0
deserts
def end_meal():
with register:
pay()while deserts == 0:
register.wait()-= 1
deserts return # leave restaurant with desert
def make_desert():
with register:
+= 1
deserts # requeue 1 waiting customer register.notify()
Once a year the restaurant had a special eat-for-free day as a marketing strategy. On those days at the end of your meal you lined up to each get a custom desert.
from queue import SimpleQueue
= SimpleQueue()
desert_line
def special_end_meal():
= desert_line.get() # waits if none are ready
desert return # leave with desert
def special_make_desert():
desert_line.put(custom_desert())
The restaurant was on a very busy road were it was not safe to leave on your own. Instead, an attendant would periodically stop traffic and let out anyone waiting to leave. Everyone has to wait: new departures while traffic is stopped are not let go until the next time traffic is stopped. Well, almost everyone; there was a tiny window of time when you can show up between the attendant letting people out and the attendant blocking any new arrivals, but you have t get your timing exactly right to hit that time window.
from threading import Event
= Event()
may_leave
def leave():
may_leave.wait()
depart()
def stop_traffic():
set() # all waiters stop waiting
may_leave.# race condition at this time may_leave.wait() doesn't wait
# new arrivals must wait may_leave.clear()