""" Dining Philosophers, one of the best-known examples of race condions with 1. a circular table 2. `count` seats, each with a philosopher in it 3. a single chopstick between each pair of philosophers 4. philosophers need two chopsticks to eat, and put down their chopsticks after each mouthful Ph2 ┌───────┐ │ \ ○ / │ Ph1 │○ ○│ Ph3 │ / ○ \ │ └───────┘ Ph4 """ from threading import Thread, Lock from time import sleep from random import uniform class Chopstick: """Lock cannot be a base class, so we use a wrapper instead. The __enter__ and __exit__ methods are used by `with` blocks""" def __init__(self, name): self.lock = Lock() self.name = name def __enter__(self, *args, **kargs): self.lock.__enter__(*args, **kargs) def __exit__(self, *args, **kargs): self.lock.__exit__(*args, **kargs) class Philosopher(Thread): def __init__(self, name, left, right): super().__init__() self.left = left self.right = right self.name = name self.round = 0 def run(self): while True: with self.left: print(self.name,'has', self.left.name) with self.right: print(self.name,'has', self.right.name) sleep(uniform(0,0.001)) # eat self.round += 1 print(self.name,f'put down the chopsticks ({self.round})') sleep(uniform(0,0.001)) # think count = 3 utensil = [Chopstick(f'chopstick {i+1}') for i in range(count)] seat = [Philosopher(f'Philosopher {i+1}', utensil[i-1], utensil[i]) for i in range(count)] for p in seat: p.start()