|
CSP for Java (JCSP) 1.0-rc4 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object | +--jcsp.lang.Parallel
This constructor taks an array of CSProcesses and returns a CSProcess that is the parallel composition of its process arguments.
Shortcut to the Constructor and Method Summaries.
Note: for those familiar with the occam multiprocessing language, the Parallel class gives the semantics of the PAR construct. However, none of the parallel usage checks mandated by occam can be made by the Java compiler, so we need to exercise that care ourselves. For instance, do not try to run the same process instance more than once in parallel and, generally, watch out for accidentally shared objects! Running different instances of the same process in parallel is, of course, allowed.
CSProcesses can be added to a Parallel object either via
the constructor
or the addProcess
methods.
If a call to addProcess is made while the run method is executing,
the extra process(es) will not be included in the network until the next time
run is invoked.
CSProcesses can be removed from a Parallel object
via the removeProcess
or
removeAllProcesses
method.
If a call to removeProcess or removeAllProcesses
is made while the run method is executing, the process will
not be removed from the network until the next time run is
invoked.
Note: to add/remove a process to/from a network whilst it is running,
see the ProcessManager
class.
__________________________________________________________________________ | | | | | ________________ ________________ ________________ | | | | | | | | | | |Here is the JCSP code:NumbersInt
| |SquaresInt
| |FibonacciInt
| | | |________________| |________________| |________________| | | \ | / | | \ | / | | a[0] v a[1] v a[2] v | | \ | / | | ___\__________________|___________________/___ | | | | | | | | | | |ParaplexInt
| | | | | | | |______________________________________________| | | | | | | | | b v | | | | | _____________|______________ | | | | | | | | | | | in-lined below | | | | | | | |____________________________| | | | | ParaplexIntTest | |__________________________________________________________________________|
import jcsp.lang.*; import jcsp.plugNplay.*; class ParaplexIntTest { public static void main (String[] args) { final One2OneChannelInt[] a = One2OneChannelInt.create (3); final One2OneChannel b = new One2OneChannel (); new Parallel ( new CSProcess[] { new NumbersInt (a[0]), new SquaresInt (a[1]), new FibonacciInt (a[2]), new ParaplexInt (a, b), new CSProcess () { public void run () { System.out.println ("\n\t\tNumbers\t\tSquares\t\tFibonacci\n"); while (true) { int[] data = (int[]) b.read (); for (int i = 0; i < data.length; i++) { System.out.print ("\t\t" + data[i]); } System.out.println (); } } } } ).run (); } }This example tabulates columns of (respectively) natural numbers, perfect squares and the Fibonacci sequence. At this level, we are only aware of five communicating processes: three that generate the respective sequences of integers, one that multiplexes a single item from each sequence into a single packet and the in-lined process that receives this packet and tabulates its contents. And, at this level, that is all we need to think about.
However, clicking on any of the generator processes reveals sub-networks
(and, in the case of SquaresInt
and
FibonacciInt
, sub-sub-networks).
Altogether, the example contains 28 parallel processes -- 18 of them
high-level (and non-terminating) and 10 low-level
(and transient, but repeatedly re-invoked). One of the key benefits of CSP is that
its semantics are compositional -- i.e. we do not have to reason about
all those 28 processes at the same time to reason about how they behave
in this application. We can build up the complexity in layers.
Note: the above example is just to build fluency with the CSP/occam concept of parallel composition and to show how easy it is. The network decomposes into fine-grained stateless components that would be excellent if we were refining this application down to a silicon (e.g. FPGA) implementation -- but for software running on a uni-processor JVM, we would not suggest going quite so far!
Note: the above layered network of communicating parallel processes is completely deterministic. It will produce the same results regardless of the scheduling characteristics of the underlying JVM and regardless of its physical distribution on to separate processors (and their relative speeds). This default determinism is one of the founding strengths of CSP concurrency that reinforces confidence in the systems we build with it.
Non-determinism, of course, needs to be addressed for many applications
and is catered for in JCSP by its Alternative
construct
(which corresponds to the CSP external choice operator and occam ALT),
by its any-1, 1-any and any-any channels
(e.g. Any2OneChannel
) and by the overwriting semantics
that can be defined for its channels (e.g. OverWriteOldestBuffer
).
The fact that non-determinism has to be explicitly introduced reduces
the chance of overlooking race-hazards caused by that non-determinism.
ParaplexInt
process used in the high-level example above:
package jcsp.plugNplay.ints; import jcsp.lang.*; public final class ParaplexInt implements CSProcess { private final ChannelInputInt[] in; private final ChannelOutput out; public ParaplexInt (final ChannelInputInt[] in, final ChannelOutput out) { this.in = in; this.out = out; } public void run () { final ProcessReadInt[] inputProcess = new ProcessReadInt[in.length]; for (int i = 0; i < in.length; i++) { inputProcess[i] = new ProcessReadInt (in[i]); } Parallel parInput = new Parallel (inputProcess); int[][] data = new int[2][in.length]; // double-buffer int index = 0; // initial buffer index while (true) { parInput.run (); int[] buffer = data[index]; // grab a buffer for (int i = 0; i < in.length; i++) { buffer[i] = inputProcess[i].value; } out.write (buffer); index = 1 - index; // switch buffers } } }Note that the Parallel object (parInput) is constructed once and contains an array of processes (
ProcessReadInt
), each of which performs only a single channel
input and, then, terminates. Each time it is run (parInput.run inside
the loop), all those sub-processes run concurrently -- the parallel run terminating
when, and only when, all those sub-processes have terminated. See the documentation
of ParaplexInt
for the motivation for this low-level concurrency (and for
the double-buffering).
java.lang.Thread
s to run the first
(n - 1) of its processes, running the last one in its own thread of control.
After each run of the Parallel CSProcess
, all those threads
are parked for reuse in the next run. Thus in the above low-level
application, the overhead for Java thread creation for the internal concurrency
is only incurred on its first cycle. All these implementation Threads
are daemons and, so, will terminate if everything else terminates.
If a Parallel process has finished its run() and is not going
to be used again, its parked threads may be unparked and terminated by invoking
its releaseAllThreads
method. This will release
the memory used by those threads.
CSProcess
,
ProcessManager
,
Sequence
Constructor Summary | |
Parallel()
Construct a new Parallel object initially without any processes. |
|
Parallel(CSProcess[] processes)
Construct a new Parallel object with the processes specified. |
Method Summary | |
void |
addProcess(CSProcess process)
Add the process to the Parallel object. |
void |
addProcess(CSProcess[] newProcesses)
Add the array of processes to the Parallel object. |
static void |
destroy()
Deprecated. Do not use this method! |
int |
getNumberProcesses()
|
void |
releaseAllThreads()
Release all threads saved by the Parallel object for future runs - the threads all terminate and release their associated workspaces. |
void |
removeAllProcesses()
Remove all processes from the Parallel object. |
void |
removeProcess(CSProcess process)
Remove the process from the Parallel object. |
void |
run()
Run the parallel composition of the processes registered with this Parallel object. |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
public Parallel()
public Parallel(CSProcess[] processes)
processes
- The processes to be executed in parallelMethod Detail |
public static void destroy()
ProcessManager
objects.public void addProcess(CSProcess process)
process
- the CSProcess to be addedpublic void addProcess(CSProcess[] newProcesses)
processes
- the CSProcesses to be addedpublic void removeProcess(CSProcess process)
process
- the CSProcess to be removedpublic void removeAllProcesses()
public void releaseAllThreads()
process
- the CSProcess to be removedpublic int getNumberProcesses()
public void run()
Implementation note: In its first run, only (numProcesses - 1) Threads are created to run the processes -- the last process is executed in the invoking Thread. Sunsequent runs reuse these Threads (so the overhead of thread creation happens only once).
run
in interface CSProcess
|
CSP for Java (JCSP) 1.0-rc4 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |