# From: "Dat Nguyen" # Subject: DiningAndDrinkingPhilosophers # Date: Thu, 06 May 2004 10:43:20 -0400 # # Besides the binary semaphore which flipflops to allow access to a resource # one at a time, regular semaphore mediates multiple requests to a resource. # This element can be realized in C-Kermit easily. I offer the Philosophers # some bottles wine which are managed by a winepool object. The philosopher # object sends the request to the winepool which assigns an availble bottle to # the philosopher or puts him on a queue for the bottle with the least numbers # of waiting philosophers for it. To create a fierce competition for the wine, # only a few bottles are to serve all philosophers. The more philosophers # there are, some more bottles are served. # # Since the original concept is solid, it can accomdate this extension # smoothly. # # Please enjoy the modern version of the philosopher society: The # DiningAndDrinkingPhilosophers attached here. # take class define randnum { # \%1 random seed while true { if {\fsexpr(> (let rd \frandom(\%1)) 0)} return \m(rd) } } class Semaphore define Semaphore::new: { (setq \%1.Semaphore.stat -1) _asg \%1.Semaphore.Queue | (\%1) } define Semaphore>>acquire { (++ \%1.Semaphore.stat) if > \%1.Semaphore.stat 0 { _asg \%1.Semaphore.Queue \m(\%1.Semaphore.Queue)\%2| echo \%2 waits for \m(\%2.\%1.ChopStick) } else { echo \%2 grabs \m(\%2.\%1.ChopStick) } (! \%1.Semaphore.stat) } define Semaphore>>release { (-- \%1.Semaphore.stat) local \&w[] if > \fsplit(\m(\%1.Semaphore.Queue),&w,|) 0 { _asg \%1.Semaphore.Queue \freplace(\m(\%1.Semaphore.Queue),|\&w[1]|,|) DiningPhilosophers add: \&w[1] echo \&w[1] grabs \m(\&w[1].\%1.ChopStick) } (\%1) } define Semaphore>>inspect { echo \%1 \m(\%1.Semaphore.stat) echo \%1 \m(\%1.Semaphore.Queue) } class Bottle define Bottle::new: { (setq \%1.Bottle.stat -1) _asg \%1.Bottle.Queue | (\%1) } define Bottle>>val { (\%1.Bottle.stat) } define Bottle>>acquire { (++ \%1.Bottle.stat) if > \%1.Bottle.stat 0 { _asg \%1.Bottle.Queue \m(\%1.Bottle.Queue)\%2| echo \%2 waits for bottle \%1 } else { echo \%2 grabs bottle \%1 } (! \%1.Bottle.stat) } define Bottle>>release { (-- \%1.Bottle.stat) echo \%2 returns \%1 local \&w[] if > \fsplit(\m(\%1.Bottle.Queue),&w,|) 0 { _asg \%1.Bottle.Queue \freplace(\m(\%1.Bottle.Queue),|\&w[1]|,|) DiningPhilosophers add: \&w[1] echo \&w[1] grabs Bottle \%1 } (\%1) } class Philosopher define Philosopher::new:leftChopStick:rightChopStick:place: { # \%2 leftChopStick # \%3 rightChopStick # \%4 no. seat if {\fsexpr(mod \%4 2)} { # odd _asg \%1.firstChopStick \%2 _asg \%1.secondChopStick \%3 } else { # even _asg \%1.firstChopStick \%3 _asg \%1.secondChopStick \%2 } _asg \%1.\%2.ChopStick left ChopStick _asg \%1.\%3.ChopStick right ChopStick _asg \%1.Philosopher.act thinking (setq \%1.Philosopher.timeRepeat (randnum 15)) (\%1) } define Philosopher>>act { if {\fsexpr(> (-- \%1.Philosopher.timeRepeat) 0)} return 1 (setq \%1.Philosopher.timeRepeat (randnum 50)) (\%1 '\m(\%1.Philosopher.act)) } define Philosopher>>thinking { echo \%1 is thinking _asg \%1.Philosopher.act getChopStick (1) # line up in the process queue } define Philosopher>>getChopStick { (AND (\%1 'getFirstChopStick) (\%1 'getSecondChopStick)) } define Philosopher>>getFirstChopStick { _asg \%1.Philosopher.act getSecondChopStick (\m(\%1.firstChopStick) 'acquire \%1) } define Philosopher>>getSecondChopStick { _asg \%1.Philosopher.act eat (\m(\%1.secondChopStick) 'acquire \%1) } define Philosopher>>eat { echo \%1 is eating _asg \%1.Philosopher.act grabBottle (1) } define Philosopher>>grabBottle { _asg \%1.Philosopher.act drink (WinePool 'grabBottle: '\%1) } define Philosopher>>drink { echo \%1 is drinking _asg \%1.Philosopher.act dropBottle (1) } define Philosopher>>dropBottle { _asg \%1.Philosopher.act release_ChopSticks WinePool dropBottle: \%1 (1) } define Philosopher>>release_ChopSticks { echo \%1 releases both Chopsticks _asg \%1.Philosopher.act sleep (\m(\%1.firstChopStick) 'release) (\m(\%1.secondChopStick) 'release) (1) } define Philosopher>>sleep { echo \%1 is sleeping _asg \%1.Philosopher.act wakeup (1) } define Philosopher>>wakeup { echo \%1 wakes up _asg \%1.Philosopher.act thinking (1) } define Philosopher>>inspect { echo \fsexp(\m(\%1.leftChopStick) 'inspect) and \fsexp(\m(\%1.rightChopStick) 'inspect) (\%1) } class winePoolMgr define winePoolMgr::new:numberOfBottles: { local \%i _asg \%1.winePool.numberOfBottles \%2 for \%i 1 \%2 1 { Bottle new: \%1.Bottle.\%i _asg \%1.Bottle.\%i.has | } } define winePoolMgr>>grabBottle: { local \%i \%m \%k (setq \\\\%m 9999999) for \%i 1 \%1.winePool.numberOfBottles 1 { (if (< (\%1.Bottle.\%i 'val) \%m) (. (setq \\\\%k \%i) (setq \\\\%m (\%1.Bottle.\%i 'val)) ) ) } _asg \%1.\%2.hasBottle \%k # Philosopher has this bottle (\%1.Bottle.\%k 'acquire \%2) } define winePoolMgr>>dropBottle: { (let \\\\%k \%1.\%2.hasBottle) \%1.Bottle.\%k release \%2 } class Process define Process>>run { while true { local \&w[] (if (\fsplit(\m(\%1.Process.Queue),&w,|)) (\%1 'remove: '\&w[1])) (if (\&w[1] 'act) (\%1 'add: \&w[1])) } } define Process>>add: { _asg \%1.Process.Queue \m(\%1.Process.Queue)\%2| (\%1) } define Process>>remove: { _asg \%1.Process.Queue \freplace(\m(\%1.Process.Queue),|\%2|,|) (\%1) } define Process>>inspect { echo \m(\%1.Process.Queue) (\%1) } define Process::new:number: { # \%2 Number of Philosophers and ChopSticks _asg \%1.Process.Queue | local \%i \%n for \%i 1 \%2 1 { Semaphore new: chopstk_\%i } for \%i 1 \%2 1 { (let \\\\%L \%i \\\\%R (+ (mod \%i \%2) 1)) Philosopher new: Philosopher_\%i leftChopStick: chopstk_\%L rightChopStick: chopstk_\%R place: \%i \%1 add: Philosopher_\%i } (setq \\\\%n (floor (/ \%2 7))) (if (== 0 \%n) (setq \\\\%n 1)) winePoolmgr new: winePool numberOfBottles: \%n (\%1) } define ASKME { local \%n while true { ask \%n { Number of Philosophers: } if not def \%n continue if not numeric \%n { echo Not numeric - "\%n" continue } break } if < \%n 2 { echo One needs at least two chopsticks to eat rice. Sorry! EXIT } return \%n } (Process 'new: 'DiningPhilosophers 'number: (askme)) DiningPhilosophers run