CSP for Java
(JCSP) 1.0-rc4

jcsp.lang
Class Any2OneCallChannel

java.lang.Object
  |
  +--jcsp.lang.Guard
        |
        +--jcsp.lang.AltingChannelAccept
              |
              +--jcsp.lang.Any2OneCallChannel
All Implemented Interfaces:
ChannelAccept, Serializable

public abstract class Any2OneCallChannel
extends AltingChannelAccept
implements Serializable

This is the super-class for any-to-one interface-specific CALL channels, safe for use by many clients and one server.

Shortcut to the Constructor and Method Summaries.

Description

Please see One2OneCallChannel for general information about CALL channels. Documented here is information specific to this any-1 version.

Converting a Method Interface into a Variant CALL Channel

Constructing a any-1 CALL channel for a specific interface follows exactly the same pattern as in the 1-1 case. Of course, it must extend Any2OneCallChannel rather than One2OneCallChannel.

For example, using the same Foo interface as before, we derive:

 import jcsp.lang.*;
 
 public class Any2OneFooChannel extends Any2OneCallChannel implements Foo {
 
   ...  same body as One2OneFooChannel
 
 }
 

Calling a CALL Channel

All the client needs to see is the method interface implemented by the CALL channel. So far as the client is concerned, therefore, there is no difference between any of the varieties of CALL channel - it just makes the call.

Accepting a CALL Channel

The mechanics of accepting a CALL channel are the same for all varieties. However, the server should declare which kind (or kinds) it allows to be attached:
 import jcsp.lang.*;
 
 class B implements CSProcess, Foo {
 
   private final ChannelAccept in;
 
   public B (final One2OneFooChannel in) {         // original constructor
     this.in = in;
   }
 
   public B (final Any2OneFooChannel in) {        // additional constructor
     this.in = in;
   }
 
   ...  rest as before
 
 }
 
When wrapping the above to hide its raw method interface, don't forget to include the extra constructor(s):
 import jcsp.lang.*;
 
 public class B2 implements CSProcess {            // no Foo interface
 
   private final B b;
 
   public B2 (final One2OneFooChannel in) {        // original constructor
     b = new B (in);
   }
 
   public B2 (final Any2OneFooChannel in) {       // additional constructor
     b = new B (in);
   }
 
   public void run () {
     b.run ();
   }
 
 }
 

ALTing on a CALL Channel

The server may ALT on a any-1 CALL channel, just as it may ALT on a 1-1 one. As before, it needs to make its intentions explicit. So, in the above example, the first field declaration of B needs to become:
   private final AltingChannelAccept in;
 
See below for an example of ALTing between CALL channels.

Building a CALL Channel Network

Network building with CALL channels is the same as building with ordinary channels. First construct the channels and, then, construct the processes - plugging in the channels as required and running them in Parallel.

For example, the network consisting of one server and several clients:

      _____    _____         _____
     |     |  |     |       |     |
     |  A  |  |  A  |  ...  |  A  |
     |_____|  |_____|       |_____|                         ______________
        |        |             |              c            |              |
   ------------------------------------------<->-----------|      B2      |
                                      Any2OneFooChannel    |______________|
 
where A is unchanged from its definition in One2OneCallChannel, is implemented by:
     Any2OneFooChannel c = new Any2OneFooChannel ();
 
     final A[] aClients = new A[n_aClients];
     for (int i = 0; i < aClients.length; i++) {
       aClients[i] = new A (c);
     }
 
     new Parallel (
       new CSProcess[] {
         new Parallel (aClients),
         new B2 (c)
       }
     ).run ();
 

Example

This is a CALL channel version of the Wot-no-Chickens example:
     ________    ________         ________
    |        |  |        |       |        |
    |  Chef  |  |  Chef  |  ...  |  Chef  |
    |________|  |________|       |________|                    _______________
        |           |                |           supply       |               |
  -------------------------------------------------<->--------|               |
                                                              |    Canteen    |
  -------------------------------------------------<->--------|               |
        |           |                |           service      |_______________|
     ___|____    ___|____         ___|____ 
    |        |  |        |       |        |
    |  Phil  |  |  Phil  |  ...  |  Phil  |
    |________|  |________|       |________|
 
The service CALL channel replaces the request/deliver channel pair of the earlier example. Previously, the philosopher had to perform two actions to get a chicken - a request.write followed by a deliver.read. Now, its interaction with the canteen is a single CALL on service.takeChicken.

The supply CALL channel replaces the ordinary channel of the same name. Previously, the chef still had to perform two actions to supply the chickens - a supply.write followed by a second supply.write. This was to model the extended period while the chef set down the chickens in the canteen. The first communication synchronised the chef with the canteen, getting its exclusive attention. The canteen then executed the set-down delay before accepting the second communication and, hence, releasing the chef. Now, this interaction is a single CALL on supply.freshChickens.

The other difference with the earlier example is that the college now employs many chefs. This has two minor impacts. It needs to be able to support any-1 CALLs on its supply channel (as well as on service). Secondly, with all those chefs, it needs to be able to refuse further supplies of chicken if it has run of room.

The Canteen

There are two other differences in design between the canteen server here and the CALL channel servers documented above and in One2OneCallChannel. The first is trivial - we have inlined the real server as an anonymous inner class of the public Canteen wrapper. The second is more subtle, but also trivial. Often, a CALL channel is constructed for a specific server interface and there is no intention for it to be used for communicating with any other server. In which case, it makes sense to tie that interface, together with its corresponding CALL channel, into the server as inner declarations.

So, the Canteen first publishes its two specific interfaces and matching CALL channels. The CALL channels follow the defined pattern, omitting the optional setting of selected (since each interface contains only one method):

 import jcsp.lang.*;
 
 class Canteen implements CSProcess {
 
   public static interface Service {
     public int takeChicken (String philId);
   }
 
   public static class One2OneServiceChannel
    extends One2OneCallChannel implements Service {
     public int takeChicken (String philId) {
       join ();
       int n = ((Service) server).takeChicken (philId);
       fork ();
       return n;
     }
   }
 
   public static class Any2OneServiceChannel
    extends Any2OneCallChannel implements Service {
     public int takeChicken (String philId) {
       join ();
       int n = ((Service) server).takeChicken (philId);
       fork ();
       return n;
     }
   }
 
   public static interface Supply {
     public int freshChickens (String chefId, int value);
   }
 
   public static class Any2OneSupplyChannel
    extends Any2OneCallChannel implements Supply {
     public int freshChickens (String chefId, int value) {
       join ();
       int n = ((Supply) server).freshChickens (chefId, value);
       fork ();
       return n;
     }
   }
 
Note that we have defined both 1-1 and any-1 versions of the Service CALL channel. This example makes use only of the any-1 variant - the other will be used in a later exercise.

Next we set up the constructor and the local fields for saving its parameters:

   private final AltingChannelAccept service;   // shared from all Philosphers
   private final AltingChannelAccept supply;    // shared from all Chefs
   private final int serviceTime;               // how long a philosopher spends in the canteen
   private final int supplyTime;                // how long a chef spends in the canteen
   private final int maxChickens;               // maximum number of chickens in the canteen
 
   public Canteen (Any2OneServiceChannel service, Any2OneSupplyChannel supply,
                   int serviceTime, int supplyTime, int maxChickens) {
     this.service = service;
     this.supply = supply;
     this.serviceTime = serviceTime;
     this.supplyTime = supplyTime;
     this.maxChickens = maxChickens;
   }
 
Now, we need to combine the exported interfaces into a single one so that the inner process can be created (anonymously) by this wrapper's run method:
   private interface inner extends CSProcess, Service, Supply {};
 
   public void run () {
 
     new inner () {
 
       private int nChickens = 0;
       private int nSupplied = 0;
 
       private final CSTimer tim = new CSTimer ();
 
Impementations of the required CALL interfaces come next:
       public int takeChicken (String philId) {                // pre : nChickens > 0
         System.out.println ("   Canteen -> " + philId + " : one chicken ordered ... "
                                              + nChickens + " left ... ");
         tim.sleep (serviceTime);
         nChickens--;
         nSupplied++;
         System.out.println ("   Canteen -> " + philId + " : one chicken coming down ... "
                                              + nChickens + " left ... ["
                                              + nSupplied + " supplied]");
         return 1;
       }
 
       public int freshChickens (String chefId, int value) {   // pre : nChickens < maxChickens
         System.out.println ("   Canteen <- " + chefId + " : ouch ... make room ... ");
         tim.sleep (supplyTime);
         nChickens += value;
         int sendBack = nChickens - maxChickens;
         if (sendBack > 0) {
           nChickens = maxChickens;
           System.out.println ("   Canteen <- " + chefId
                                                + " : full up ... sending back " + sendBack);
         } else {
           sendBack = 0;
         }
         System.out.println ("   Canteen <- " + chefId + " : more chickens ... "
                                              + nChickens + " now available ... ");
         return sendBack;
       }
 
and the run method that conducts everything:
       public void run () {
 
         final Alternative alt = new Alternative (new Guard[] {supply, service});
         final boolean[] precondition = {true, false};
         final int SUPPLY = 0;
         final int SERVICE = 1;
 
         System.out.println ("   Canteen : starting ... ");
         while (true) {
           precondition[SERVICE] = (nChickens > 0);
           precondition[SUPPLY] = (nChickens < maxChickens);
           switch (alt.fairSelect (precondition)) {
             case SUPPLY: 
               supply.accept (this);      // new batch of chickens from a chef
             break;
             case SERVICE:
               service.accept (this);     // a philosopher wants a chicken
             break;
           }
         }
 
       }
 
Finally, don't forget to run this inner process:
     }.run ();
 
   }
 
 }
 

The Philosopher

As in the original example, philosophers spend their time thinking, feeling hungry, calling on the canteen and, once served, eating. Except, of course, for greedy philosophers who never stop to think:
 import jcsp.lang.*;
 
 class Phil implements CSProcess {
 
   private final String id;
   private final Canteen.Service service;
   private final int thinkTime;
   private final int eatTime;
   private final boolean greedy;
 
   public Phil (String id, Canteen.Service service,
                int thinkTime, int eatTime, boolean greedy) {
     this.id = id;
     this.service = service;
     this.thinkTime = thinkTime;
     this.eatTime = eatTime;
     this.greedy = greedy;
   }
 
   public void run () {
     final CSTimer tim = new CSTimer ();
     int nEaten = 0;
     while (true) {
       if (! greedy) {
         System.out.println ("   Phil " + id + " : thinking ... ");
         tim.sleep (thinkTime);  // thinking
       }
       System.out.println ("   Phil " + id + " : gotta eat ... ");
       int chicken = service.takeChicken (id);
       nEaten++;
       System.out.println ("   Phil " + id + " : mmm ... that's good ["
                                      + nEaten + " so far]");
       tim.sleep (eatTime);      // eating
     }
   }
 
 }
 

The Chef

Chefs cook chickens in batches of batchSize, taking batchTime milliseconds per batch. When a batch is ready, the chef supplies it to the canteen. The chef has to wait until the canteen is prepared to take it and, then, helps to set down the batch (before returning with any for which there was no space) - all this happens during the CALL of supply.freshChickens:
 import jcsp.lang.*;
 
 class Chef implements CSProcess {
 
   private final String id;
   private final int batchSize;
   private final int batchTime;
   private final Canteen.Supply supply;
 
   public Chef (String id, int batchSize, int batchTime, Canteen.Supply supply) {
     this.id = id;
     this.batchSize = batchSize;
     this.batchTime = batchTime;
     this.supply = supply;
   }
 
   public void run () {
 
     final CSTimer tim = new CSTimer ();
 
     int nReturned = 0;
     int nSupplied = 0;
 
     while (true) {
       System.out.println ("   Chef " + id + " : cooking ... "
                                      + (batchSize - nReturned) + " chickens");
       tim.sleep (batchTime);
       System.out.println ("   Chef " + id + " : "
                                      + batchSize + " chickens, ready-to-go ... ");
       nReturned = supply.freshChickens (id, batchSize);
       nSupplied += (batchSize - nReturned);
       System.out.println ("   Chef " + id + " : "
                                      + nReturned + " returned ["
                                      + nSupplied + " supplied]");
     }
   }
 
 }
 

The Clock

The college is feeling generous and provides a clock. This just ticks away, delivering time-stamps roughly every second (and maintaining real-time). It is independent of the rest of the system.
 import jcsp.lang.*;
 
 class Clock implements CSProcess {
 
   public void run () {
 
     final CSTimer tim = new CSTimer ();
     final long startTime = tim.read ();
 
     while (true) {
       int tick = (int) (((tim.read () - startTime) + 500)/1000);
       System.out.println ("[TICK] " + tick);
       tim.sleep (1000);
     }
 
   }
 
 }
 

The College

Despite the greedy behaviour of philosopher 0 (Bill), nobody starves in this college. Three chefs are provided with differing cooking speeds and batch sizes. Pierre is the original lightning chef, cooking 4 chickens in 2 seconds flat. Henri is more leisurely, taking 20 seconds to cook his batch of 10. Sid has been sent down by the new owners of the college, who are into mass catering. He produces 100 chickens every 150 seconds, which is a bit silly since the canteen has only space for 50. Still, it enables Bill to get really sick!

For convenience, the college network diagram is reproduced here - this time including the clock and naming some of the characters:

                                                  _________
                                                 |         |
   ___________    ___________    ___________     |  Clock  |
  |           |  |           |  |           |    |_________|
  |   Pierre  |  |   Henri   |  |    Sid    |
  |___________|  |___________|  |___________|                  _______________
        |              |              |          supply       |               |
  -------------------------------------------------<->--------|               |
                                                              |    Canteen    |
  -------------------------------------------------<->--------|               |
         |           |                |          service      |_______________|
      ___|____    ___|____         ___|____ 
     |        |  |        |       |        |
     |  Bill  |  | Hilary |  ...  | Monica |
     |________|  |________|       |________|
 
Here is the code:
 import jcsp.lang.*;
 
 class College implements CSProcess {
 
   public void run () {
 
     final String[] philId = {"Bill", "Hilary", "Gennifer", "Paula", "Monica"};
 
     final int thinkTime = 3000;             // 3 seconds
     final int eatTime = 100;                // 100 milliseconds
 
     final int serviceTime = 0;              // 0 seconds
     final int supplyTime = 3000;            // 3 seconds
     final int maxChickens = 50;
 
     final Canteen.Any2OneServiceChannel service
       = new Canteen.Any2OneServiceChannel ();
     final Canteen.Any2OneSupplyChannel supply
       = new Canteen.Any2OneSupplyChannel ();
 
     final Phil[] phils = new Phil[philId.length];
     for (int i = 0; i < phils.length; i++) {
       phils[i] = new Phil (philId[i], service, thinkTime, eatTime, i == 0);
     }
 
     new Parallel (
       new CSProcess[] {
         new Clock (),
         new Canteen (service, supply, serviceTime, supplyTime, maxChickens),
         new Parallel (phils),
         new Chef ("Pierre", 4, 2000, supply),      // chefId, batchSize, batchTime
         new Chef ("Henri", 10, 20000, supply),     // chefId, batchSize, batchTime
         new Chef ("Sid", 100, 150000, supply)      // chefId, batchSize, batchTime
       }
     ).run ();
 
   }
 
   public static void main (String argv[]) {
     new College ().run ();
   }
 
 }
 

A Note about System.out and Other Non-Blocking Monitors

The college network diagram and code hides a key player that quietly coordinates the reporting of all activity - System.out. All the processes share this object as a common resource, making heavy and concurrent demands on its println service. Why is this safe?

Consider a Java object whose public methods are all synchronized but contain no invocations of wait or notify (a passive non-blocking monitor). Such an object is equivalent to a CSProcess serving one or more any-1 CALL channels (whose interfaces reflect those synchronized methods) and whose run consists of an endless loop that does nothing except unconditionally accept any CALL.

So, a simple non-blocking monitor is always safe to share between concurrent JCSP processes and, currently, carries less overheads than its active server equivalent. See DisplayList for an example from the JCSP library. Another example is java.io.PrintStream, of which System.out is an instance. Its print/println methods are synchronized on itself (although this does not seem to be documented and you have to look hard at the code to find out). So, to show the full story, the above diagram possibly needs an overlay that adds a System.out process servicing a any-1 println CALL channel, with all the other processes as clients. This is left as an exercise.

Of course, it would be nice if such monitors were accessed via an interface, so that client processes had neither direct visibilty of them nor concern about their behaviour. A problem with the above college is that System.out - and the concept of printing a line of text - is burnt into the code of all its processes. If we wanted to change the output of the college from a scrolling text display into some graphics animation, all those processes would have to be changed.

A better design would pass in channel (or CALL channel or non-blocking monitor) interfaces to each of the college processes. These would merely report their identities and states by writing to (or calling or invoking) those interfaces. To reproduce the current display, all those interfaces would be instanced by a single any-1 channel (or CALL channel or monitor) connected to a simple server that responds by making System.out.println invocations appropriate to the information passed. For other effects, connect in other servers. Note that the college processes do not have to be connected to the same server - each could be connected to a separate server and these servers connected into a graphics animation network (incorporating, for example, processes from jcsp.awt). The point is that the college processes would need no changing to drive whatever was constructed. This is also left as an exercise.

Further Thoughts on the Canteen Design

The decision to bind in the CALL channel (and associated inteface) definitions as inner classes of Canteen does not fit comfortably with the above observations. However, processes servicing Canteen.Any2OneServiceChannel or Canteen.Any2OneSupplyChannel channels do not have to be instances of Canteen - even though that would seem to be a little odd. So, the College authorities still have freedom to install canteens with behaviours quite different to that of Canteen. [Anything with the same channel interface will fit! The interoperability of processes depends only on the compatibility of their channel interfaces. Note that this reusability owes nothing to the concept of inheritance - for example, the alternative canteens pluggable into the college network need no special sub-classing relationships.] So, if we really want to allow this flexibility, make it explicit by declaring the CALL channels separately from any of their servers.

Another design choice is to burn in CALL channel instances as part of the servers themselves. For example, the Canteen class could construct and export its service and supply channels as public and final fields (rather than import them via constructor parameters). In this case, the College builder would need to declare and name the canteen (instead of declaring and naming the channels):

 import jcsp.lang.*;
 
 class College implements CSProcess {
 
   public void run () {
 
     ...  declare constants (nPhilosophers, thinkTime etc.)
 
     final Canteen canteen = new Canteen (serviceTime, supplyTime, maxChickens);
 
     final Phil[] phils = new Phil[nPhilosophers];
     for (int i = 0; i < phils.length; i++) {
       String philId = new Integer (i).toString ();
       phils[i] = new Phil (philId, canteen.service, thinkTime, eatTime, i == 0);
     }
 
     new Parallel (
       new CSProcess[] {
         new Clock (),
         canteen,
         new Parallel (phils),
         new Chef ("Pierre", 4, 2000, canteen.supply),
         new Chef ("Henri", 10, 20000, canteen.supply),
         new Chef ("Sid", 100, 60000, canteen.supply)
       }
     ).run ();
 
   }
 
   ...  main
 
 }
 
Note that this particular burn in does not deny any flexibility to the college in choosing any particular variety of canteen. In fact, the only thing of interest to the college is that the canteen provides and services CALL channels whose interfaces are what its philosophers and chefs expect (i.e. Service and Supply). Note also that the college
network diagram has not changed.

Having gone this far, we may like to consider making the server self-starting - so that its declaration not only introduces its service channels but also brings it to life. For example, this could be done for the Canteen by adding the following as the last line of its constructor:

     new ProcessManager (this).start ();
 
Of course, the canteen instance should then be removed from the Parallel construction above.

[Warning: be careful if sub-classes are allowed (i.e. the Canteen class was not declared final). In this case, the above incantation should be optional so that each sub-class constructor can invoke a super-class constructor that omits it. If we let the super-class fire up the process, it may start running before the sub-class constructor finishes - i.e. before the process has been fully initialised. It must be the sub-class constructor that self-starts the process (as the last thing it does).]

[Note: a self-starting server exporting its own CALL (or ordinary) channels for public concurrent use corresponds to the occam3 notion of a MODULE implemented by a RESOURCE.]

Author:
P.H.Welch
See Also:
One2OneCallChannel, One2AnyCallChannel, Any2AnyCallChannel, Alternative, Serialized Form

Field Summary
protected  int selected
          This may be set during the standard calling sequence to record which method was invoked by a client.
protected  CSProcess server
          This holds a reference to a server process so that a client may make the call.
 
Constructor Summary
Any2OneCallChannel()
           
 
Method Summary
 int accept(CSProcess server)
          This is invoked by a server when it commits to accepting a CALL from a client.
protected  void fork()
          This is invoked by a client during the standard calling sequence.
protected  void join()
          This is invoked by a client during the standard calling sequence.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

server

protected CSProcess server
This holds a reference to a server process so that a client may make the call. The reference is only valid between the join and fork elements of the standard calling sequence. As shown in that sequence, it will need casting up to the relevant interface supported by the specific CALL channel derived from this class.

selected

protected int selected
This may be set during the standard calling sequence to record which method was invoked by a client. It is only safe to do this between the join and fork elements of that sequence. Either all the CALL channel methods should do this or none - in the latter case, its default value remains as zero. Its value is returned to a server as the result the server's invocation of accept.
Constructor Detail

Any2OneCallChannel

public Any2OneCallChannel()
Method Detail

accept

public int accept(CSProcess server)
This is invoked by a server when it commits to accepting a CALL from a client. The parameter supplied must be a reference to this server - see the example from One2OneCallChannel. It will not complete until a CALL has been made. If the derived CALL channel has set the selected field in the way defined by the standard calling sequence, the value returned by this method will indicate which method was called.
Parameters:
server - the server process receiving the CALL.

join

protected void join()
This is invoked by a client during the standard calling sequence. It will not complete until a server invokes an accept on this channel. In turn, that accept will not complete until the client invokes a fork, after having made its CALL on the server.

fork

protected void fork()
This is invoked by a client during the standard calling sequence. A server must have invoked an accept for the client to have got this far in the sequence - see the join. This call unblocks that accept, releasing the server and client to resume separate lives.

CSP for Java
(JCSP) 1.0-rc4

Submit a bug or feature to jcsp-team@ukc.ac.uk
Version 1.0-rc4 of the JCSP API Specification (Copyright 1997-2000 P.D.Austin and P.H.Welch - All Rights Reserved)
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.