# From: Dat Thuc Nguyen -*-kermit-*- # Date: Mon, 03 May 2004 15:12:56 -0400 # Subject: The Art of Programming in C-Kermit # # From time to time I sent in C-Kermit scripts that solve some problems people # also solved in other programming languages. # # Today I am sending in a program that's difficult since it requires # the notions of semaphore, process, timer and concurrency. # # The "dinning philosophers" problem is stated in Operating System Concepts by # Peterson and Silberschatz, 1985, pp. 347-348. # # Requires the 'class' module. # # Version 2: I fine tune the Dinning Philosophers script to # accomodate any numbers of hungry Philosophers instead of only five. 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 { local s (setq s (++ \%1.Semaphore.stat)) if > s 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) } (! s) } 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 Philosopher define Philosopher::new:leftChopStick:rightChopStick:place: { # \%2 leftChopStick # \%3 rightChopStick (setq \%1.leftChopStick \%2) (setq \%1.rightChopStick \%3) (setq \%1.Philosopher.Number \%4) _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 { (-- \%1.Philosopher.timeRepeat) if == \m(\%1.Philosopher.timeRepeat) 0 { (setq \%1.Philosopher.timeRepeat (randnum 50)) return \fsexpr(\%1 '\m(\%1.Philosopher.act)) } else { return 1 # line up in the process queue } } 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 if {\fsexpr(mod \%1.Philosopher.Number 2)} { # odd return \fsexpr(\m(\%1.leftChopStick) 'acquire \%1) } else { # even return \fsexpr(\m(\%1.rightChopStick) 'acquire \%1) } } define Philosopher>>getSecondChopStick { _asg \%1.Philosopher.act eat if {\fsexpr(mod \%1.Philosopher.Number 2)} { # odd return \fsexpr(\m(\%1.rightChopStick) 'acquire \%1)) } else { # even return \fsexpr(\m(\%1.leftChopStick) 'acquire \%1)) } } define Philosopher>>eat { echo \%1 is eating _asg \%1.Philosopher.act release_ChopSticks (1) } define Philosopher>>release_ChopSticks { echo \%1 releases both Chopsticks _asg \%1.Philosopher.act sleep (\m(\%1.leftChopStick) 'release) (\m(\%1.rightChopStick) '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 Process define Process>>run { while true { local \&w[] \%n asg \%n \fsplit(\m(\%1.Process.Queue),&w,|) if = 0 \%n break \%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 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 } (\%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 } return \%n } (Process 'new: 'DiningPhilosophers 'number: (askme)) DiningPhilosophers run