"The Dining Philosophers Problem is a classic concurrency problem that illustrates synchronization issues and the challenges of resource allocation in concurrent systems. It was formulated by Edsger Dijkstra in 1965. The problem is typically described in terms of five philosophers sitting around a table, each philosopher alternately thinking and eating. However, there are only five chopsticks available for them to share, with each philosopher requiring two chopsticks to eat.
- There are five philosophers sitting around a circular table. - Each philosopher alternates between thinking and eating. To eat, a philosopher needs two chopsticks, one from their left and one from their right. - Chopsticks can only be held by one philosopher at a time. A philosopher must be holding both chopsticks simultaneously to eat. - Once a philosopher finishes eating, they put down both chopsticks and start thinking again."
import threading
import time
import random
import signal
class Chopstick(threading.Semaphore):
def __init__(self, name):
threading.Semaphore.__init__(self)
self.name = name
class Philosopher(threading.Thread):
def __init__(self, name, left_chopstick, right_chopstick, color, time_limit):
threading.Thread.__init__(self)
self.stopped = False
self.name = color + name + '\033[00m'
self.left_chopstick = left_chopstick
self.right_chopstick = right_chopstick
self.time_limit = time_limit
self.time_limit_reached = threading.Event()
def pickup(self):
if not self.stopped:
self.left_chopstick.acquire()
self.right_chopstick.acquire()
def putdown(self):
self.left_chopstick.release()
self.right_chopstick.release()
def stop(self):
self.stopped = True
def run(self):
start_time = time.time()
while not self.stopped and not self.time_limit_reached.is_set():
print(f'{self.name} is waiting.')
self.pickup()
if self.stopped or self.time_limit_reached.is_set():
return
print(f'{self.name} is eating.')
time.sleep(random.randint(3, 10))
self.putdown()
print(f'{self.name} is thinking.')
if not self.stopped:
time.sleep(random.randint(3, 15))
if time.time() - start_time >= self.time_limit:
self.time_limit_reached.set()
if __name__ == '__main__':
c1 = Chopstick('c1')
c2 = Chopstick('c2')
c3 = Chopstick('c3')
c4 = Chopstick('c4')
c5 = Chopstick('c5')
chopsticks = [c1, c2, c3, c4, c5]
colors = {
'red': '\033[0;31m',
'yellow': '\033[33m',
'green': '\033[32m',
'blue': '\033[34m',
'purple': '\033[35m'
}
names = ['Kashyap', 'Deep', 'Jenil', 'Darshil', 'Dhairya']
random.shuffle(names)
time_limit = int(input("Enter the time limit for the dinner in seconds: "))
philosophers = [
Philosopher(names[0], c1, c2, colors['red'], time_limit),
Philosopher(names[1], c2, c3, colors['yellow'], time_limit),
Philosopher(names[2], c3, c4, colors['green'], time_limit),
Philosopher(names[3], c4, c5, colors['blue'], time_limit),
Philosopher(names[4], c5, c1, colors['purple'], time_limit)
]
def init():
print('Philosophers:')
for p in philosophers:
print(f'{p.name} ', end='')
print('\n\nDinner is served!\n')
def start():
for p in philosophers:
p.start()
for p in philosophers:
p.join()
def exit(signum, frame):
for p in philosophers:
p.stop()
print('\nDinner has ended. Waiting for everyone to finish up!\n')
signal.signal(signal.SIGINT, exit)
init()
start()
print("\nDone! 👌")