home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / multtsk / cpm25d / philo.pas < prev    next >
Pascal/Delphi Source File  |  1994-04-28  |  9KB  |  315 lines

  1. {$I cpmswitc.inc}
  2. {$M 16384,0,655360 }
  3.  
  4. {--------------------------------------------------------------------------
  5.  
  6. PHILO.PAS  (Solution to the Dining Philosophers problem)
  7.  
  8. This program requires the CPMULTI Multitasking Toolkit and Turbo Pascal
  9. 5.0 or later.
  10.  
  11. January 1994
  12.  
  13. Copyright (C) 1994 (USA)        Copyright (C) 1989-1994
  14. Hypermetrics                    Christian Philipps Software-Technik
  15. PO Box 9700 Suite 363           Duesseldorfer Str. 316
  16. Austin, TX  78758-9700          D-47447 Moers
  17.                                 Germany
  18.  
  19. The Dining Philosophers problem is a classic problem in computer
  20. science dealing with resource contention. For a good discussion
  21. of it, see Computer Language magazine, September 1987.
  22.  
  23. ---------------------------------------------------------------------------}
  24.  
  25. program DiningPhilosophers;
  26.  
  27. uses {.U-} CRT, CPMulti;
  28.  
  29. type   PhiloStateType = (Thinking, Hungry, Eating);
  30.  
  31. const  Philosophers = 8;
  32.        PhiloPos     : array[1..Philosophers] of 
  33.                         record
  34.                           left, top,
  35.                           right, bottom : byte;
  36.                         end
  37.                     = ((left:35;top:1;right:45;bottom:3),
  38.                        (left:56;top:3;right:66;bottom:5),
  39.                        (left:65;top:9;right:75;bottom:11),
  40.                        (left:56;top:15;right:66;bottom:17),
  41.                        (left:35;top:17;right:45;bottom:19),
  42.                        (left:14;top:15;right:24;bottom:17),
  43.                        (left:5;top:9;right:15;bottom:11),
  44.                        (left:14;top:3;right:24;bottom:5));
  45.  
  46. var    PhiloState : array[1..Philosophers] of PhiloStateType;
  47.        PhiloSem   : array[1..Philosophers] of Pointer;
  48.        Critical   : Pointer;                           { Semaphores }
  49.        Critical1  : Pointer;
  50.        N          : Byte;
  51.  
  52. {-------------------------------------------------------------------}
  53.  
  54. procedure Normal;
  55. begin
  56.   TextColor(White);
  57.   TextBackground(Black);
  58. end;
  59.  
  60. {-------------------------------------------------------------------}
  61.  
  62. procedure NormalBlink;
  63. begin
  64.   TextColor(White+Blink);
  65.   TextBackground(Black);
  66. end;
  67.  
  68. {-------------------------------------------------------------------}
  69.  
  70. procedure Reverse;
  71. begin
  72.   TextColor(Black);
  73.   TextBackground(White);
  74. end;
  75.  
  76. {-------------------------------------------------------------------}
  77.  
  78. procedure Frame (X1,Y1,X2,Y2:Byte);
  79. var N : Byte;
  80. begin
  81.   GotoXY(X1,Y1);
  82.   Write('╔');
  83.   for N := 1 to X2-X1-1 do
  84.     Write('═');
  85.   Write('╗');
  86.   for N := 1 to Y2-Y1-1 do
  87.   begin
  88.     GotoXY(X1,Y1+N);
  89.     Write('║');
  90.     GotoXY(X2,Y1+N);
  91.     Write('║');
  92.   end;
  93.     GotoXY(X1,Y2);
  94.   Write('╚');
  95.   for N := 1 to X2-X1-1 do
  96.     Write('═');
  97.   Write('╝');
  98. end;
  99.  
  100. {-------------------------------------------------------------------}
  101.  
  102. function Left(P:Byte):Byte;
  103.  
  104. { Determine the left neighbor of a philosopher. }
  105.  
  106. begin
  107.   if P = 1 then 
  108.     Left := Philosophers
  109.   else 
  110.     Left := Pred(P);
  111. end;
  112.  
  113. {-------------------------------------------------------------------}
  114.  
  115. function Right(P:Byte):Byte;
  116.  
  117. { Determine the right neighbor of a philosopher. }
  118.  
  119. begin
  120.   if P = Philosophers then 
  121.     Right := 1
  122.   else 
  123.     Right := Succ(P);
  124. end;
  125.  
  126. {-------------------------------------------------------------------}
  127.  
  128. procedure Contemplate(PhilNo:Byte);
  129.  
  130. { This procedure is run when a philosopher thinks. }
  131.  
  132. begin
  133.   with PhiloPos[PhilNo] do
  134.   begin
  135.     SemWait(Critical1);
  136.     Normal;
  137.     GotoXY(Succ(Left),Succ(Top));
  138.     Write(' Think!! ');
  139.     SemSignal(Critical1);
  140.   end;
  141.   Sleep(Seconds(3));
  142. end;
  143.  
  144. {-------------------------------------------------------------------}
  145.  
  146. procedure Eat(PhilNo:Byte);
  147.  
  148. { This procedure is run when a philosopher eats. }
  149.  
  150. begin
  151.   with PhiloPos[PhilNo] do
  152.   begin
  153.     SemWait(Critical1);
  154.     Reverse;
  155.     GotoXY(Succ(Left),Succ(Top));
  156.     Write(' Slurp!! ');
  157.     SemSignal(Critical1);
  158.   end;
  159.   Sleep(Seconds(2));
  160. end;
  161.  
  162. {-------------------------------------------------------------------}
  163.  
  164. procedure Check(PhilNo:Byte);
  165.  
  166. { Check each neighbor of the philosopher, in order to determine
  167.   whether the forks are free. This is always the case when neither 
  168.   neighbor is currently eating. }
  169.  
  170. begin
  171.   if PhiloState[PhilNo] <> Hungry then             { We're busy. }
  172.     Exit;
  173.  
  174.   if (PhiloState[Left(PhilNo)]  <> Eating) and
  175.      (PhiloState[Right(PhilNo)] <> Eating) then 
  176.   begin
  177.     PhiloState[PhilNo] := Eating;      { OK, we can eat.        }
  178.     SemSignal(PhiloSem[PhilNo]);       { Increase signal count. }
  179.   end;
  180. end;
  181.  
  182. {-------------------------------------------------------------------}
  183.  
  184. procedure GrabForks(PhilNo:Byte);
  185.  
  186. { Pick up the forks lying to the right and left of the
  187.   philosopher's plate.  If a fork is not available,
  188.   the philosopher languishes in the wait-state and is  
  189.   seized by terrible hunger!  }
  190.  
  191. begin
  192.   SemWait(Critical);                     { Critical section. }
  193.   with PhiloPos[PhilNo] do
  194.   begin
  195.     NormalBlink;
  196.     GotoXY(Succ(Left),Succ(Top));
  197.     Write(' Hungry! ');
  198.     Sleep(Seconds(1) shr 1);
  199.   end;
  200.   PhiloState[PhilNo] := Hungry;         { We're hungry. }
  201.   Check(PhilNo);                        { Can we eat??? }
  202.   SemSignal(Critical);                  { Release critical section. }
  203.   SemWait(PhiloSem[PhilNo]);            { If not, let's wait. }
  204. end;
  205.  
  206. {-------------------------------------------------------------------}
  207.  
  208. procedure LayForksDown(PhilNo:Byte);
  209.  
  210. { Lay down the forks and yield to our neighbor, in case he can
  211.   eat now. }
  212.  
  213. begin
  214.   SemWait(Critical);                     { Critical section.            }
  215.   PhiloState[PhilNo] := Thinking;        { We're thinking again.        }
  216.   Check(Left(PhilNo));                   { Test left neighbor.          }
  217.   Check(Right(PhilNo));                  { Test right neighbor.         }
  218.   SemSignal(Critical);                   { End of the critical section. }
  219. end;
  220.  
  221. {-------------------------------------------------------------------}
  222.  
  223. {$F+}
  224. procedure Philosoph(P:Pointer);
  225.  
  226. {
  227.   The body of the philosopher task.
  228.   This procedure demonstrates that Turbo Pascal tasks
  229.   are fundamentally able to run while code-sharing.
  230.   The prerequisite is that every philosopher should have 
  231.   his own stack; this is guaranteed by CreateTask.
  232. }
  233.  
  234. var MyNo : Byte;
  235. begin
  236.   MyNo := Byte(P);
  237.   with PhiloPos[MyNo] do
  238.   begin
  239.     SemWait(Critical1);
  240.     Normal;
  241.     Frame(left,top,right,bottom);
  242.     GotoXY(Succ(left),Succ(Top));
  243.     Write(' Think!! ');
  244.     SemSignal(Critical1);
  245.   end;
  246.   repeat                              { The life of a philosopher:      }
  247.     Contemplate(MyNo);                { We think a little...            }
  248.     GrabForks(MyNo);                  { ...reach for our forks...       }
  249.     Eat(MyNo);                        { ...eat a couple of mouthfuls... }
  250.     LayForksDown(MyNo);               { ...and relinquish the forks.    }
  251.   until False;
  252. end;
  253. {$F-}
  254.  
  255. {-------------------------------------------------------------------}
  256.  
  257. procedure DrawTable;
  258.  
  259. { Set up the demo. }
  260.  
  261. begin
  262.   Normal;
  263.   ClrScr;
  264.   Frame(20,6,60,14);
  265.   Window(22,8,58,13);
  266.   Writeln('   The Dining Philosophers Problem');
  267.   Writeln('      ─────────────────────────');
  268.   Writeln('           (Dijkstra 1965)'^J);
  269.   Writeln('      Christian Philipps,  6/88');
  270.   Window(1,20,80,25);
  271.   Writeln('Every philosopher has a plate of spaghetti in front of him. Between each');
  272.   Writeln('two plates lies a fork. Every philosopher needs two forks, if he wants');
  273.   Writeln('to eat from his pile of slippery spaghetti...');
  274.   Writeln('A philosopher thinks for 3 seconds and eats for 2 seconds. The transition');
  275.   Write  ('(hunger) is for demonstration purposes at least 1/2 seconds long!');
  276.   Window(1,1,80,25);
  277. end;
  278.  
  279. {-------------------------------------------------------------------}
  280.  
  281. begin
  282.   DrawTable;
  283.   if CreateSem(Critical) <> Sem_OK then 
  284.   begin
  285.     Writeln('Error in the creation of Critical semaphore!');
  286.     Halt;
  287.   end;
  288.   if CreateSem(Critical1) <> Sem_OK then 
  289.   begin
  290.     Writeln('Error in the creation of Critical1 semaphore!');
  291.     Halt;
  292.   end;
  293.   for N := 1 to Philosophers do
  294.   begin
  295.     PhiloState[N] := Thinking;
  296.     if CreateSem(PhiloSem[N]) <> Sem_OK then 
  297.     begin
  298.       Writeln('Error in the creation of PhiloSem[',N,']');
  299.       Halt;
  300.     end
  301.     else 
  302.       SemClear(PhiloSem[N]);
  303.   end;
  304.   for N := 1 to Philosophers do
  305.     if CreateTask(Philosoph,Pointer(N),Pri_User,500) < 0 then 
  306.     begin
  307.       Writeln('Error in the creation of philosopher #',N,'!');
  308.       Halt;
  309.     end;
  310.   repeat
  311.     Sleep(Seconds(1));
  312.   until KeyPressed;
  313.   Normal;
  314. end.
  315.