|
CSP for Java (JCSP) 1.1-rc4 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
public interface CSProcess
This is the JCSP interface for a process - an active component that encapsulates the data structures on which it operates.
In this JCSP binding of the CSP model into Java, a process is an instance of a class implementing this CSProcess interface. Its actions are defined by the run method.
Running processes interact solely via CSP channels, events or carefully synchronised access to shared objects -- not by calling each other's methods. These passive objects form the CSP interface to a process. They are not present in the Java interface and must be configured into each process via public constructors and/or mutators when it is not running (i.e. before and in between runs). It is safe to extract information from the process via accessor methods, but only after (or in between) runs.
For other general information, see the JCSP overview.
import org.jcsp.lang.*; ... other imports class ProcessExample implements CSProcess { ... private/protected shared synchronisation objects (channels etc.) ... private/protected state information ... public constructors ... public configuration/inspection methods (when not running) ... private/protected support methods (part of a run) ... public run method (the process starts here) }The pattern of use for these methods is simple and well-disciplined. The public constructors and configuration methods must install the shared synchronisation objects into their private/protected fields. They may also initialise other private/protected state information. The public configuration/inspection methods (simple sets and gets) may be invoked only when this process is not running and are the responsibility of a single process only -- usually the process that constructed it. That process is also responsible for invoking the public run method that kicks this one into life (usually, via a
Parallel
or ProcessManager
intermediary).
The private support methods are triggered only by the run
method and express the live behaviour of this process.
A process instance may have several lives but these must, of course, be consecutive. Different instances of the same process class may, also of course, be alive concurrently. Reconfiguration of a process via its configuration/inspection methods may only take place between lives. Dynamic reconfiguration of a live process may take place -- but only with the active cooperation of the process (for example, through channel communication).
This is not to say that the semantics of processes connected in parallel are simply the sum of the semantics of each individual process -- just that those semantics should contain no surprises. Value can added just through the nature of the parallel composition itself. For example, connect simple stateless processes into a channel feedback-loop, give them some external wires and we get a component that contains state.
The process design pattern defines some powerful simplifications that bring us that control. Backed up with the theory of CSP, it also addresses and offers solutions to some fundamental issues in concurrency and multi-threading.
In unconstrained OO, threads and objects are orthogonal notions -- sometimes dangerously competitive. Threads have no internal structure and can cross object boundaries in spaghetti-like trails that relate objects together in a way that has little correspondence to the original OO design. A process combines these ideas into a single concept, gives it structure and maintains strong encapsulation by guarding the distribution and use of references with some strict (and checkable) design rules. A process may be wired up in parallel with other processes to form a network -- which is itself a process. So, a process may have sub-processes that have sub-sub-processes ad infinitum. This is the way the world works ...
The simplicity of the process design pattern is that each process can be considered individually as an independent serial program, interacting with external I/O devices (the synchronisation objects -- channels etc.). At the other end of those devices may lie other processes, but that is of no concern to the consideration of this process. All our past skills and intuition about serial programming can safely be applied. The new skills needed to design and use parallel process networks sit alongside those earlier skills and no cross-interference takes place.
Parallel
and Alternative
classes.
Here is another very simple one:
import org.jcsp.lang.*; // LaunchControl is a process to control the launch of a space rocket. // It is configured with a countdown time in seconds -- this must be above // a minimum threshold, MIN_COUNTDOWN, else the launch is immediately aborted. // There are two control lines, abort and hold, that respectively abort // or hold the launch if signalled. The hold is released by a second // signal on the same line. // During countdown, the count is reported by outputting on the countdown // channel. // If not aborted, LaunchControl fires the rocket (by outputting on its fire // channel) when the countdown reaches zero. An ABORTED launch is also // reported on this fire channel. // After a successful or aborted launch, LaunchControl terminates. // The status attribute records whether the launch was FIRED or ABORTED // and may then be inspected. public class LaunchControl implements CSProcess { public static final int MIN_COUNTDOWN = 10; public static final int FIRED = 0; public static final int HOLDING = 1; public static final int COUNTING = 2; public static final int ABORTED = 3; public static final int UNDEDFINED = 4; private final int start; private final AltingChannelInputInt abort; private final AltingChannelInputInt hold; private final ChannelOutputInt countdown; private final ChannelOutputInt fire; private int status = UNDEDFINED; public LaunchControl (final int start, final AltingChannelInputInt abort, final AltingChannelInputInt hold, final ChannelOutputInt countdown, final ChannelOutputInt fire) { this.start = start; this.abort = abort; this.hold = hold; this.countdown = countdown; this.fire = fire; } public int getStatus () { // inspection method return status; // (can only be used in between runs) } public void run () { final CSTimer tim = new CSTimer (); // JCSP timers have final long oneSecond = 1000; // millisecond granularity long timeout = tim.read () + oneSecond; // compute first timeout final Alternative alt = new Alternative (new Guard[] {abort, hold, tim}); final int ABORT = 0; final int HOLD = 1; final int TICK = 2; int count = start; boolean counting = (start >= MIN_COUNTDOWN); // abort if bad start while ((count > 0) && counting) { countdown.write (count); // public address system tim.setAlarm (timeout); // set next timeout switch (alt.priSelect ()) { case ABORT: // abort signalled abort.read (); // clear the signal counting = false; break; case HOLD: // hold signalled long timeLeft = timeout - tim.read (); // time till next tick hold.read (); // clear the signal fire.write (HOLDING); // signal rocket hold.read (); // wait for the release timeout = tim.read () + timeLeft; // recompute next timeout fire.write (COUNTING); // signal rocket break; case TICK: // timeout expired count--; timeout += oneSecond; // compute next timeout break; } } status = (counting) ? FIRED : ABORTED; // set status attribute fire.write (status); // signal rocket (go/nogo) if (counting) countdown.write (0); // complete countdown } }
Parallel
,
PriParallel
,
Alternative
,
ChannelInput
,
ChannelOutput
,
One2OneChannel
,
Any2OneChannel
,
One2AnyChannel
,
Any2AnyChannel
,
ChannelInputInt
,
ChannelOutputInt
,
One2OneChannelInt
,
Any2OneChannelInt
,
One2AnyChannelInt
,
Any2AnyChannelInt
,
ProcessManager
Method Summary | |
---|---|
void |
run()
This defines the actions of the process. |
Method Detail |
---|
void run()
|
CSP for Java (JCSP) 1.1-rc4 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |