home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ckscripts / dining-drinking-philosophers < prev    next >
Lisp/Scheme  |  2020-01-01  |  7KB  |  281 lines

  1. # From: "Dat Nguyen"
  2. # Subject: DiningAndDrinkingPhilosophers
  3. # Date: Thu, 06 May 2004 10:43:20 -0400
  4. #
  5. # Besides the binary semaphore which flipflops to allow access to a resource 
  6. # one at a time, regular semaphore mediates multiple requests to a resource. 
  7. # This element can be realized in C-Kermit easily. I offer the Philosophers 
  8. # some bottles wine which are managed by a winepool object. The philosopher 
  9. # object sends the request to the winepool which assigns an availble bottle to 
  10. # the philosopher or puts him on a queue for the bottle with the least numbers 
  11. # of waiting philosophers for it. To create a fierce competition for the wine, 
  12. # only a few bottles are to serve all philosophers. The more philosophers 
  13. # there are, some more bottles are served.
  14. # Since the original concept is solid, it can accomdate this extension 
  15. # smoothly.
  16. # Please enjoy the modern version of the philosopher society: The 
  17. # DiningAndDrinkingPhilosophers attached here.
  18. take class
  19.  
  20. define randnum {
  21. # \%1 random seed
  22.     while true {
  23.         if {\fsexpr(> (let rd \frandom(\%1)) 0)} return \m(rd)
  24.     }
  25. }
  26.  
  27. class Semaphore
  28.  
  29. define Semaphore::new: {
  30.     (setq \%1.Semaphore.stat -1)
  31.     _asg \%1.Semaphore.Queue |
  32.     (\%1)
  33. }
  34.  
  35. define Semaphore>>acquire {
  36.     (++ \%1.Semaphore.stat)
  37.     if > \%1.Semaphore.stat 0 {
  38.         _asg \%1.Semaphore.Queue \m(\%1.Semaphore.Queue)\%2|
  39.         echo \%2 waits for \m(\%2.\%1.ChopStick)
  40.     } else {
  41.         echo \%2 grabs \m(\%2.\%1.ChopStick)
  42.     }
  43.     (! \%1.Semaphore.stat)
  44. }
  45.  
  46. define Semaphore>>release {
  47.     (-- \%1.Semaphore.stat)
  48.     local \&w[] 
  49.     if > \fsplit(\m(\%1.Semaphore.Queue),&w,|) 0 {
  50.         _asg \%1.Semaphore.Queue \freplace(\m(\%1.Semaphore.Queue),|\&w[1]|,|)
  51.         DiningPhilosophers add: \&w[1]
  52.         echo \&w[1] grabs \m(\&w[1].\%1.ChopStick)
  53.     }
  54.     (\%1)
  55. }
  56.  
  57. define Semaphore>>inspect {
  58.     echo \%1 \m(\%1.Semaphore.stat)
  59.     echo \%1 \m(\%1.Semaphore.Queue)
  60. }
  61.  
  62. class Bottle
  63. define Bottle::new: {
  64.     (setq \%1.Bottle.stat -1)
  65.     _asg \%1.Bottle.Queue |
  66.     (\%1)
  67. }
  68. define Bottle>>val {
  69.     (\%1.Bottle.stat)
  70. }
  71. define Bottle>>acquire {
  72.     (++ \%1.Bottle.stat)
  73.     if > \%1.Bottle.stat 0 {
  74.         _asg \%1.Bottle.Queue \m(\%1.Bottle.Queue)\%2|
  75.         echo \%2 waits for bottle \%1
  76.     } else {
  77.         echo \%2 grabs bottle \%1
  78.     }
  79.     (! \%1.Bottle.stat)
  80. }
  81. define Bottle>>release {
  82.     (-- \%1.Bottle.stat)
  83.     echo \%2 returns \%1
  84.     local \&w[] 
  85.     if > \fsplit(\m(\%1.Bottle.Queue),&w,|) 0 {
  86.         _asg \%1.Bottle.Queue \freplace(\m(\%1.Bottle.Queue),|\&w[1]|,|)
  87.         DiningPhilosophers add: \&w[1]
  88.         echo \&w[1] grabs Bottle \%1
  89.     }
  90.     (\%1)
  91. }
  92.  
  93. class Philosopher
  94.  
  95. define Philosopher::new:leftChopStick:rightChopStick:place: {
  96. # \%2 leftChopStick
  97. # \%3 rightChopStick
  98. # \%4 no. seat
  99.     if {\fsexpr(mod \%4 2)} {       # odd
  100.         _asg \%1.firstChopStick \%2
  101.         _asg \%1.secondChopStick \%3
  102.     } else {            # even
  103.         _asg \%1.firstChopStick \%3
  104.         _asg \%1.secondChopStick \%2
  105.     }
  106.     _asg \%1.\%2.ChopStick left ChopStick
  107.     _asg \%1.\%3.ChopStick right ChopStick
  108.     _asg \%1.Philosopher.act thinking
  109.     (setq \%1.Philosopher.timeRepeat (randnum 15))
  110.     (\%1)
  111. }
  112.  
  113. define Philosopher>>act {
  114.     if {\fsexpr(> (-- \%1.Philosopher.timeRepeat) 0)} return 1
  115.     (setq \%1.Philosopher.timeRepeat (randnum 50))
  116.     (\%1 '\m(\%1.Philosopher.act))
  117. }
  118.  
  119. define Philosopher>>thinking {
  120.     echo \%1 is thinking
  121.     _asg \%1.Philosopher.act getChopStick
  122.     (1)     # line up in the process queue
  123. }
  124.  
  125. define Philosopher>>getChopStick {
  126.     (AND (\%1 'getFirstChopStick) (\%1 'getSecondChopStick))
  127. }
  128.  
  129. define Philosopher>>getFirstChopStick {
  130.     _asg \%1.Philosopher.act getSecondChopStick
  131.     (\m(\%1.firstChopStick) 'acquire \%1)
  132. }
  133.  
  134. define Philosopher>>getSecondChopStick {
  135.     _asg \%1.Philosopher.act eat
  136.     (\m(\%1.secondChopStick) 'acquire \%1)
  137. }
  138.  
  139. define Philosopher>>eat {
  140.     echo \%1 is eating
  141.     _asg \%1.Philosopher.act grabBottle
  142.     (1)
  143. }
  144.  
  145. define Philosopher>>grabBottle {
  146.     _asg \%1.Philosopher.act drink
  147.     (WinePool 'grabBottle: '\%1)
  148. }
  149.  
  150. define Philosopher>>drink {
  151.     echo \%1 is drinking
  152.     _asg \%1.Philosopher.act dropBottle
  153.     (1)
  154. }
  155.  
  156. define Philosopher>>dropBottle {
  157.     _asg \%1.Philosopher.act release_ChopSticks
  158.     WinePool dropBottle: \%1
  159.     (1)
  160. }
  161.  
  162. define Philosopher>>release_ChopSticks {
  163.     echo \%1 releases both Chopsticks
  164.     _asg \%1.Philosopher.act sleep
  165.     (\m(\%1.firstChopStick) 'release)
  166.     (\m(\%1.secondChopStick) 'release)
  167.     (1)
  168. }
  169.  
  170. define Philosopher>>sleep {
  171.     echo \%1 is sleeping
  172.     _asg \%1.Philosopher.act wakeup
  173.     (1)
  174. }
  175.  
  176. define Philosopher>>wakeup {
  177.     echo \%1 wakes up
  178.     _asg \%1.Philosopher.act thinking
  179.     (1)
  180. }
  181.  
  182. define Philosopher>>inspect {
  183.     echo \fsexp(\m(\%1.leftChopStick) 'inspect) and \fsexp(\m(\%1.rightChopStick) 'inspect)
  184.     (\%1)
  185. }
  186.  
  187. class winePoolMgr
  188. define winePoolMgr::new:numberOfBottles: {
  189.     local \%i
  190.     _asg \%1.winePool.numberOfBottles \%2
  191.     for \%i 1 \%2 1 {
  192.         Bottle new: \%1.Bottle.\%i
  193.         _asg \%1.Bottle.\%i.has |
  194.     }
  195. }
  196.  
  197. define winePoolMgr>>grabBottle: {
  198.     local \%i \%m \%k
  199.     (setq \\\\%m 9999999)
  200.     for \%i 1 \%1.winePool.numberOfBottles 1 {
  201.         (if (< (\%1.Bottle.\%i 'val) \%m)
  202.             (. (setq \\\\%k \%i) (setq \\\\%m (\%1.Bottle.\%i 'val))
  203.             )
  204.         )
  205.     }
  206.     _asg \%1.\%2.hasBottle \%k      # Philosopher has this bottle
  207.     (\%1.Bottle.\%k 'acquire \%2)
  208. }
  209.  
  210. define winePoolMgr>>dropBottle: {
  211.     (let \\\\%k \%1.\%2.hasBottle)
  212.     \%1.Bottle.\%k release \%2
  213. }
  214.  
  215. class Process
  216.  
  217. define Process>>run {
  218.     while true {
  219.         local \&w[]
  220.         (if (\fsplit(\m(\%1.Process.Queue),&w,|)) (\%1 'remove: '\&w[1]))
  221.         (if (\&w[1] 'act) (\%1 'add: \&w[1]))
  222.     }
  223. }
  224.  
  225. define Process>>add: {
  226.     _asg \%1.Process.Queue \m(\%1.Process.Queue)\%2|
  227.     (\%1)
  228. }
  229.  
  230. define Process>>remove: {
  231.     _asg \%1.Process.Queue \freplace(\m(\%1.Process.Queue),|\%2|,|)
  232.     (\%1)
  233. }
  234.  
  235. define Process>>inspect {
  236.     echo \m(\%1.Process.Queue)
  237.     (\%1)
  238. }
  239.  
  240. define Process::new:number: {
  241. # \%2   Number of Philosophers and ChopSticks
  242.     _asg \%1.Process.Queue |
  243.     local \%i \%n
  244.     for \%i 1 \%2 1 {
  245.         Semaphore new: chopstk_\%i
  246.     }
  247.     for \%i 1 \%2 1 {
  248.         (let \\\\%L \%i \\\\%R (+ (mod \%i \%2) 1))
  249.         Philosopher new: Philosopher_\%i leftChopStick: chopstk_\%L rightChopStick: chopstk_\%R place: \%i
  250.         \%1 add: Philosopher_\%i
  251.     }
  252.     (setq \\\\%n (floor (/ \%2 7)))
  253.     (if (== 0 \%n) (setq \\\\%n 1))
  254.     winePoolmgr new: winePool numberOfBottles: \%n
  255.     (\%1)
  256. }
  257.  
  258. define ASKME {
  259.     local \%n
  260.     while true {
  261.         ask \%n { Number of Philosophers: }
  262.         if not def \%n continue
  263.         if not numeric \%n {
  264.             echo Not numeric - "\%n"
  265.             continue
  266.         }
  267.         break
  268.     }
  269.     if < \%n 2 {
  270.         echo One needs at least two chopsticks to eat rice. Sorry!
  271.         EXIT
  272.     }
  273.     return \%n
  274. }
  275.  
  276. (Process 'new: 'DiningPhilosophers 'number: (askme))
  277. DiningPhilosophers run
  278.