Reputation: 127
I start to learn python and multithreading. I am trying to do the dining philosopher problem. I use class philosophers(threading.thread). But when I put in some sample and create threads, it has error AssertionError: group argument must be None for now.
import threading
import time
from random import randint
exitFlag = 0
class philosophers(threading.Thread):
def __int__(self, phi, hungry, eat):
threading.Thread.__int__(self)
#super(philosophers.self)__int__()
self.phi = phi
self.hungry = hungry
self.eat = eat
def hungry(self):
time.sleep(self.hungry)
print("Philosopher" +(self.phi) + "is hungry and want to eat" + "\n")
startEat()
def startEat(self):
left = self.phi
right = (self.phi+1)%5
left.acquire()
if right.locked():
left.release()
else:
right.acquire()
time.sleep(self.eat)
right.release()
left.release()
print("Philosopher" +(self.phi) + "is finished" + "\n")
#def run()
thread1 = philosophers(1, 5, 3)
thread2 = philosophers(2, 4, 2)
#thread3 = philosophers(3, 6, 7)
#thread4 = philosophers(4, 2, 8)
#thread5 = philosophers(5, 3, 4)
thread1.start()
thread2.start()
#thread3.start()
#thread4.start()
#thread5.start()
thread1.join()
thread2.join()
#thread3.join()
#thread4.join()
#thread5.join()
Upvotes: 1
Views: 6194
Reputation: 142794
Your main problem is simple typo: it has to be __init__
instead of __int__
(in two places)
But there are other probles.
When you execute thread.start()
then it create thread in system and executes thread.run()
so you have to rename def hungry
into def run
left
and right
are normal numbers int
. You can't use them with acquire
, locked
, release
. You need objects threading.Lock for this.
It is not mistake but you could keep threads
on list and then it is simpler to use start()
and join()
on all threads
. And you don't have to change this part of code even if you change number of threads
on list.
PEP 8 -- Style Guide for Python Code
Last problem is that I'm not sure if your algorithm is correct.
As for me Philosopner
can eat (time.sleep(self.eat)
) even if he doesn't have both forks.
And at start left.acquire()
can give False
but you don't check it.
EDIT:
I added more print()
to see values in variable and which part of code is executed and I get:
Philosopher 4 is hungry and want to eat
Philosopher 4 left fork: True
Philosopher 4 right fork: True
Philosopher 4 is eating
Philosopher 5 is hungry and want to eat
Philosopher 2 is hungry and want to eat
Philosopher 2 left fork: True
Philosopher 2 right fork: True
Philosopher 2 is eating
Philosopher 1 is hungry and want to eat
Philosopher 1 left fork: True
Philosopher 1 doesn't have forks
Philosopher 3 is hungry and want to eat
Philosopher 2 is finished
Philosopher 3 left fork: True
Philosopher 3 doesn't have forks
Philosopher 1 is finished
Philosopher 4 is finished
Philosopher 5 left fork: True
Philosopher 5 right fork: True
Philosopher 5 is eating
Philosopher 3 is finished
Philosopher 5 is finished
and there are 1 doesn't have forks
, 3 doesn't have forks
but they finish without eating.
It may need some loop to try again get forks.
import threading
import time
class Philosopher(threading.Thread): # PEP8: `UpperCaseNames` for classes.
# PEP8: This class describes single Philospher so it should have name without `s` at the end
def __init__(self, phi, hungry, eat, locks): #, *args, **kwargs):
super().__init__() #*args, **kwargs)
self.phi = phi
self.hungry = hungry
self.eat = eat
self.locks = locks
def run(self):
time.sleep(self.hungry)
print(f"Philosopher {self.phi} is hungry and want to eat")
self.start_eat() # need `self.`
def start_eat(self):
left = self.locks[self.phi-1] # Python uses indexes `[0..4]` instead of `[1..5]`
right = self.locks[self.phi%5] # Python uses indexes `[0..4]` instead of `[1..5]`
result = left.acquire()
print(f"Philosopher {self.phi} left fork:", result)
if right.locked():
left.release()
print(f"Philosopher {self.phi} doesn't have forks")
else:
result = right.acquire()
print(f"Philosopher {self.phi} right fork:", result)
print(f"Philosopher {self.phi} is eating")
time.sleep(self.eat)
if right.locked():
right.release()
if left.locked():
left.release()
print(f"Philosopher {self.phi} is finished")
# --- main ---
# 5 locks for 5 Philosophers
locks = [threading.Lock() for _ in range(5)]
threads = [
Philosopher(1, 5, 3, locks),
Philosopher(2, 4, 2, locks),
Philosopher(3, 6, 7, locks),
Philosopher(4, 2, 8, locks),
Philosopher(5, 3, 4, locks),
]
for t in threads:
t.start()
for t in threads:
t.join()
EDIT:
It seems this algorithm works correctly.
def start_eat(self):
left = self.locks[self.phi-1] # Python uses indexes `[0..4]` instead of `[1..5]`
right = self.locks[self.phi%5] # Python uses indexes `[0..4]` instead of `[1..5]`
while True:
if not left.locked():
result = left.acquire()
#print(f"Philosopher {self.phi} left fork:", result)
if right.locked():
left.release()
#print(f"Philosopher {self.phi} doesn't have forks")
else:
result = right.acquire()
#print(f"Philosopher {self.phi} right fork:", result)
print(f"Philosopher {self.phi} is eating")
time.sleep(self.eat)
right.release()
left.release()
print(f"Philosopher {self.phi} is finished")
break
Result:
Philosopher 4 is hungry and want to eat
Philosopher 4 is eating
Philosopher 5 is hungry and want to eat
Philosopher 2 is hungry and want to eat
Philosopher 2 is eating
Philosopher 1 is hungry and want to eat
Philosopher 3 is hungry and want to eat
Philosopher 2 is finished
Philosopher 1 is eating
Philosopher 1 is finished
Philosopher 4 is finished
Philosopher 5 is eating
Philosopher 3 is eating
Philosopher 5 is finished
Philosopher 3 is finished
Upvotes: 2