program philchan;

(* Dining Philsophers - channel version *)

const
  nphil = 5;
  maxphils = 4;
type
  synchan = array[0..maxphils] of  channel of synchronous;

var
  index: integer;
  getforks,putforks: synchan;

process philosopher(n: integer);
begin
  repeat
    sleep(random(5));   (* THINKING *)
    getforks[n] ! any;
    sleep(random(5));   (* EATING *)
    putforks[n] ! any;
  forever
end;  (* philosopher *)

process forkcntrl;
var
  forks: array[0..maxphils] of integer;
  i: integer;
begin
  for i := 0 to maxphils do
    forks[i] := 2;
  repeat
    select
      for i := 0 to maxphils replicate
        when forks[i] = 2 =>
          getforks[i] ? any;
          forks[(i+1) mod nphil] := forks[(i+1) mod nphil] - 1;
          forks[(i+4) mod nphil] := forks[(i+4) mod nphil] - 1;
          writeln('Philosopher ',i:1,' eats');
    or
      for i := 0 to maxphils replicate
        putforks[i] ? any;
          forks[(i+1) mod nphil] := forks[(i+1) mod nphil] + 1;
          forks[(i+4) mod nphil] := forks[(i+4) mod nphil] + 1;
    or
      terminate
    end
  forever
end;  (* forkcont *)

begin
  cobegin
    for index := 0 to maxphils do
      philosopher(index);
    forkcntrl
  coend
end.