//{{{}}} //{{{ COMMENT documentation //| //| This program shows a use of the ALT mechanism including timeouts. It is //| loosely based on the Starving Philosophers example. The Canteen now ALTs //| between the Philosophers, the Cook and a timeout. Each guard has to satisfy //| a pre-condition. Here is the College: //| //| //| 0 1 2 3 4 //| :) :) :) :) :) ___________ ________ //| | | | | | | | | | //| ---------------------<->--| Canteen |------<------| Cook | //| service/deliver |_________| supply |______| //| //| //| //| The timeout is, of course, internal to the Canteen and doesn't show up //| on this view of the system. //| //}}} import java.io.DataInputStream; import java.io.IOException; // import occam.* //{{{ class Canteen extends Thread { class Canteen extends Thread { //{{{ //{{{ COMMENT documentation // //The Canteen is an active object -- a pure SERVER process for its `supply' //and `service'/`deliver' Channels, giving priority to the former. // //Philosphers eat chickens. They queue up at the Canteen on its `service' //Channel. They only get served when chickens are available -- otherwise, //they just have to wait. Once they have got `service', they are dispensed //a chicken down the `deliver' Channel. // //The Chef cooks chickens. When a batch ready is ready, she queues up at //the Canteen on its `supply' Channel. The Canteen only accepts a new batch //when its current stock is below a maximum threshold. // //The Canteen staff get anxious when there are five of less chickens available //and complain every second this state persists. If there are no chickens left //at all, they get really cross. // //So, the Canteen is implemented as a server loop, PRI ALTing against the //supply channel (from the Chef), the service channel (from the Philosphers) //and a one-second timeout (relative from the last event). The service channel //is guarded by the availablity of chickens. The supply Channel is guarded by //there not being too many chickens already. The timeout is only set when the //chicken supply gets low. // //}}} //{{{ channels private Channel service; // shared from all Philosphers (many-1) private Channel deliver; // shared to all Philosphers (but only used 1-1) private Channel supply; // from the Chef (1-1) //}}} //{{{ constructor public Canteen (Channel service, Channel deliver, Channel supply) { this.service = service; this.deliver = deliver; this.supply = supply; start (); } //}}} //{{{ run public void run () { try { //{{{ //{{{ alt channels and guards Alternative alt = new Alternative (); Channel[] c = {supply, service}; boolean[] guard = {true, false}; int supply_index = 0; // how do I declare this as a constant? int service_index = 1; // how do I declare this as a constant? //}}} //{{{ state int n_chickens = 0; int max_chickens = 12; // how do I declare this as a constant? int low_on_chickens = 5; // how do I declare this as a constant? //}}} //{{{ starting System.out.println ("(" + System.currentTimeMillis() + ")" + " Canteen : starting ... "); //}}} while (true) { guard[supply_index] = (n_chickens < max_chickens); guard[service_index] = (n_chickens > 0); switch (alt.select (c, guard, 1000, n_chickens <= low_on_chickens)) { //{{{ supply case 0: { // case supply_index: { int value; value = supply.read (); // new batch of chickens from the Chef //{{{ bring in the tray System.out.println ("(" + System.currentTimeMillis() + ") " + "Canteen : ouch ... make room ... this dish is very hot ... "); //}}} n_chickens += value; //{{{ announce arrival of more chickens System.out.println ("(" + System.currentTimeMillis() + ") " + "Canteen : more chickens ... " + n_chickens + " now available ... "); //}}} break; } //}}} //{{{ service case 1: { // case service_index: { int dummy; dummy = service.read (); // Philosopher wants a chicken //{{{ thanks System.out.println ("(" + System.currentTimeMillis() + ") " + "Canteen : one chicken coming down ... " + (n_chickens - 1) + " left ... "); //}}} deliver.write (1); // serve one chicken n_chickens--; break; } //}}} //{{{ timeout case 2: { // case timeout_index: { if (n_chickens > 0) { //{{{ moan System.out.println ("(" + System.currentTimeMillis() + ") " + "Canteen : where are those chickens ... only " + n_chickens + " left ... "); //}}} } else { //{{{ really moan System.out.println ("(" + System.currentTimeMillis() + ") " + "Canteen : where are those ?*!%@#! chickens ... " + "none left ... "); //}}} } break; } //}}} } } //}}} } catch (InterruptedException e) {} } //}}} //}}} } //}}} //{{{ class Chef extends Thread { class Chef extends Thread { //{{{ //{{{ COMMENT documentation // //The Chef is an active object. She cooks chickens in batches, taking around 9 //seconds per batch, and then sends them to the Canteen. Although the production //of each batch is regular, the number of chickens in each batch varies. Of //course, if the Canteen is full of chickens, she has to wait. // //}}} //{{{ channels private Channel supply; //}}} //{{{ constructor public Chef (Channel supply) { this.supply = supply; start (); } //}}} //{{{ run public void run () { try { //{{{ run //{{{ state int lo_chickens = 2; int hi_chickens = 17; int n_chickens = lo_chickens; int step = 3; boolean cook_more = true; //}}} //{{{ starting System.out.println ("(" + System.currentTimeMillis() + ")" + " Chef : starting ... "); //}}} while (true) { //{{{ cook n_chickens System.out.println ("(" + System.currentTimeMillis() + ")" + " Chef : cooking ... "); //{{{ cook for around 9 seconds try {sleep (9000);} catch (InterruptedException e) {} //}}} System.out.println ("(" + System.currentTimeMillis() + ")" + " Chef : " + n_chickens + " chickens, ready-to-go ... "); //}}} supply.write (n_chickens); // supply the chickens //{{{ adjust n_chickens if (cook_more) { if (n_chickens < hi_chickens) { n_chickens += step; } else { cook_more = false; n_chickens -= step; } } else { if (n_chickens > lo_chickens) { n_chickens -= step; } else { cook_more = true; n_chickens += step; } } //}}} } //}}} } catch (InterruptedException e) {} } //}}} //}}} } //}}} //{{{ class Phil extends Thread { class Phil extends Thread { //{{{ //{{{ COMMENT documentation // //A Philosopher thinks for a while -- around 5 seconds -- and then goes to the //Canteen for food. When she gets served, which may take a while if the Canteen //has run out of chickens, she consumes it instantly. This cycle continues //indefinitely. // //}}} //{{{ parameters private int id; //}}} //{{{ channels private Channel service; private Channel deliver; //}}} //{{{ constructor public Phil (int id, Channel service, Channel deliver) { this.id = id; this.service = service; this.deliver = deliver; start (); } //}}} //{{{ run public void run () { try { //{{{ //{{{ starting System.out.println ("(" + System.currentTimeMillis() + ")" + " Phil " + id + " : starting ... "); //}}} while (true) { int chicken; //{{{ think for around 5 seconds try {sleep (5000);} catch (InterruptedException e) {} //}}} //{{{ want chicken System.out.println ("(" + System.currentTimeMillis() + ")" + " Phil " + id + " : gotta eat ... "); //}}} service.write (0); chicken = deliver.read (); //{{{ consume chicken System.out.println ("(" + System.currentTimeMillis() + ")" + " Phil " + id + " : mmm ... that's good ... "); //}}} } //}}} } catch (InterruptedException e) {} } //}}} //}}} } //}}} //{{{ class College { class College { //{{{ //{{{ COMMENT documentation // //The College consists of 5 Philosophers, a Chef and the Canteen. All are //"active" objects. The Canteen ALTs between a service Channel, shared by //all the Philosophers, a supply Channel from the Chef and a timeout. Upon //acceptance of a service request, chickens are dispensed through a delivery //Channel. // //The Canteen guards the supply Channel, refusing acceptance of more chickens //when the number already in stock exceeds a certain level. // //The Canteen guards the service Channel so that Philosophers cannot blunder //in when there are no chickens, but are held waiting in the service queue. // //The Canteen guards the timeout so that it only gets set when there are a few //chickens left. The effect is that the Canteen regularly complains when that //happens. // //The system timings are sufficiently chaotic that all these refusals can be //observed. // //}}} //{{{ main public static void main (String argv[]) { //{{{ int n_philosophers = 5; Channel service = new Channel (); Channel deliver = new Channel (); Channel supply = new Channel (); Canteen canteen = new Canteen (service, deliver, supply); Chef chef = new Chef (supply); Phil[] phil = new Phil[n_philosophers]; for (int i = 0; i < n_philosophers; i++) { phil[i] = new Phil (i, service, deliver); } //}}} } //}}} //}}} } //}}}