import threading import sys import time """ States represent the philosopher state in any moment """ class States: Thinking, Hungry, Eating = range( 0, 3 ) """ Represents the Silberschatz solution using a monitor We use a lock to allow only one thead running in all 'public' (PickUp, and PutDown) methods of this class Each chopstick is represented by a Condition variable """ class DiningPhi: # Instance variables n = 0 lock = 0 state = [] chopstick = [] # Class variable initialization def __init__( self, number ): self.lock = threading.Lock() self.n = number self.chopstick = [threading.Condition( self.lock ) for i in range( number ) ] self.state = [ States.Thinking for i in range( number ) ] # Called when a philosopher wants to eat, and needs to pickup two chopsticks def PickUp( self, who ): with self.lock: self.state[ who ] = States.Hungry self.Test( who ) if ( self.state[ who ] == States.Hungry ): self.chopstick[ who ].wait( ) # Called when a philosopher finish eating and needs to return his two chopsticks def PutDown( self, who ): with self.lock: self.state[ who ] = States.Thinking self.Test( ( who + (self.n - 1) ) % self.n ) self.Test( ( who + 1 ) % self.n ) # Check if a philosopher can pickup his two chopsticks, if none of his neighbor are not eating # Additionally check when a philosopher are returning his chopstick if one of his neighbor are Hungry def Test( self, who ): if ( ( self.state[ (who + (self.n - 1) ) % self.n ] != States.Eating ) and ( self.state[ (who + 1) % self.n ] != States.Eating ) and ( self.state[ who ] == States.Hungry ) ): self.state[ who ] = States.Eating self.chopstick[ who ].notify( ) # Print table status def Print( self, who ): desc = [ 'Thinking', 'Hungry', 'Eating' ] with self.lock: sys.stdout.write( "Filo %s [ " % who ) [ sys.stdout.write( " %s, " % desc[ self.state[ i ] ] ) for i in range( self.n ) ] sys.stdout.write( "]\n" ) # Code for the thread representing each philosopher def Filosofo( who, mesa ): for i in range(10): time.sleep(0.1) # think sys.stdout.write( " Filosofo %s va a tomar palillos \n" % who ) mesa.PickUp( who ) sys.stdout.write( " Filosofo %s esta comiendo \n" % who ) time.sleep(0.1) # (yield makes deadlock more likely) mesa.PutDown( who ) sys.stdout.write( " Filosofo %s va a pensar \n" % who ) time.sleep(0.1 * who ) mesa.Print( who ) # Code to start simulation, original problem states five philosophers def Festin( number ): mesa = DiningPhi( number ) for i in range( number ): t = threading.Thread( target=Filosofo, args=(i, mesa) ) t.start() def main(): Festin( 5 ) if __name__ == "__main__": main()