Hi Anne,
I will try to answer as many of your questions as best I can, inline.
Anne van Rossum wrote:
Dear list members,
Currently I am playing with the JCSP library. I wrote this code that has
a Writer that writes values on channelA, an Incrementer that increments
those values and a Reader that reads them and displays them at the
console:
Code:
public static void main(String[] args) {
ChannelFactory channelFactory = new StandardChannelFactory();
One2OneChannel channelA = channelFactory.createOne2One();
One2OneChannel channelB = channelFactory.createOne2One();
Parallel processPool = new Parallel(
new CSProcess[] {
new Writer(channelA.out()),
new Incrementer(channelA.in(), channelB.out()),
new Reader(channelB.in())
}
);
processPool.run();
}
Questions:
I have the following questions regarding this example:
* The CSProcesses run parallel, but it is unclear how each process gets
its processing time. Maybe the Reader gets much more cycles than the
Writer. Who knows?
Pre-empting your later question too, each CSProcess in JCSP is its own
Thread object. In a normal Parallel, all the threads have equal
priority, so the cycles are worked out by the JVM (which usually just
uses the underlying Operating System's threads). In most JCSP
programs, a process will run until it performs a channel
communication, at which point it will end up waiting for the other
party in the communication, so the thread will be scheduled out.
* The CSProcesses may be placed in any order. The Incrementer can not
read a value from its input channel when it is not available. How is
this implemented? Is the Incrementer polling channelA? Or send channelA
an event to the Incrementer?
The underlying implementation uses Java's monitors. The Incrementer
will wait on a monitor, thereby blocking it. Then other processes
will get scheduled, and once a value is written to the channel the
Incrementer will unblock again. There is no wasted time from polling
the channel.
* The nomenclature of channel.in() and channel.out() is confusing.
Channel.out() should be the endpoint of the channel, not the output of
the component where a channel starts. If a channel is a first-class
entity, it should be treated like that.
I know Peter (one of the authors) is aware of this confusion. We
think in a process-oriented manner, hence out() is from the
perspective of the process. reader() and writer() would have been
better - and may yet be used in future.
* The Parallel construct is rigid. Why is it not coupled to some kind of
"parallel" thread pool (or actually a process pool)? The implementation
of above gives all processes (supposedly) the same amount of processing
time in parallel. An "alternative" construct is also allowed. And some
implementing "priorities". That's it. How can I code other process pools
with other policies?
Put simply, JCSP does not have support for other policies. It is
something that could probably be added with some work, but the design
is simple: one process = one thread.
* On rewiring the network the One2OneChannel object has to be replaced
by an Any2OneChannel object or One2AnyChannel object, etc. How can a
process removed easily? There is a Parallel.removeProcess method that
will be executed before a call to run(). The Reader process above reads
continuously from channelB and never stops. How can I swap the Writer
for another in that case? Code after processPool.run() will not be
reached.
I do not completely understand this. Do you want to remove a process
before the Parallel is run, or while it is running. The former does
not seem very useful, the latter is dangerous. By the sounds of it
you may also want to replace processes on the fly? That would usually
be done by coding a custom process that changes its behaviour (in
effect, becoming another process) when you send it a signal.
You are correct that the code after processPool.run() will not run.
The next version of JCSP will feature a mechanism called poison, which
allows for the graceful termination of process networks, which will
allow for a clean shutdown, even of seemingly never-ending processes
like the Reader.
* How many threads are there actually? Has every channel, or every
"plug" of a channel their own thread? Or only the CSProcess objects?
Just to repeat what I said previously - each process is its own
thread. Nothing else is a thread.
Background:
What do I have in mind? I like to develop large-grain dataflow model
where the large-grain processes are aggregations of small-grain
processes (and have a better performance). If such a conversion (from
small to large-grain processes) can be automated, software will
automatically adjust to the amount and type of hardware processors
(multiple CPUs, FPGAs, etc.) For that:
* Different CSProcesses should be implemented;
* Those should be swapped for each other easily;
* Those should be compared w.r.t. performance;
* Aggregations of CSProcesses should be compared with the distinct
CSProcesses w.r.t. performance;
* Channels should be plugged somewhere else easily.
Etc. etc.
If you want different strata of processes, the next version of C++CSP
will have two layers of processes - sub-thread processes with
high-performance, composing thread-level processes. However, have you
yet tested JCSP to make sure that its performance requires this extra
work beyond the simple one process = one thread? I'm not clear if you
are needing high-performance computing or not.
As for different CSProcesses - I'm not sure how easily Java supports
mechanisms for concurrency besides the standard threads. Do you have
an idea for another way of doing things?
I hope that helps, and I hope we can find a way for JCSP to fit your
needs.
Thanks,
Neil.