[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
It was a stressing weekend!
Dear Peter,
At the same day I received your message (on Friday March 19, 19:23) about
the race hazard in the alternative (select) construct, I immediately wrote a
Java test program as you suggested to stress the CTJ-alternative construct
in the hope to encounter the race hazard (see the test program below). The
CTJ-alternative construct works fine and it seems that it does not suffer
from the mentioned race hazard. This can be explained in that the
CTJ-alternative construct is a bit different from your original select
construct. The select method in the CTJ-alternative is a private method
inside the Alternative class and I shifted some conditional synchronisation
to Guard objects. This way I can build a compositional Alternative process
and PriAlternative process in the same way as the Sequential, Parallel, and
PriParallel processes. The Guard object supports single channel input
guards, multiple channel input guards (MALT), multiple skip guards and
conditional guarding.
The CTJ-library contains an embedded scheduler (written in Java) and a
different monitor construct. We have redesigned the Java thread engine and
the Java monitor (on top of Java!). The CTJ-monitor is hidden by the
channels and is based on the article of Tony Hoare "Monitors: An Operating
System Structuring Concept" (1974). Because we redesigned the monitor in
Java, the performance overhead is significant larger. Therefore, I am
developing a C version of the CTJ-library. The C methods may provide native
methods for JDK 1.2. Yesterday, I finished the Alternative construct in C
and stressed it with the C version of the Java test program (as below). The
C version works fine and is very fast. I therefore conclude that our
CTJ-alternative construct works correct.
I have programmed with Java threads and 'synchronized' methods for some time
now. Threads and synchronising methods seem to be simple, but they are too
hard to use. I can imagine that control engineers here at our control
laboratory (and elsewhere in the world) will run away as fast as they can
when they have to write their control processes with threads and
synchronised methods. One of the reasons is that they need to understand
other synchronised methods in which they are not interested. Another reason
is that debugging with or reasoning about threads takes too much time and
effort. Threads and synchronised methods are for special skilled programmers
and they are a significant barrier for the rest of designers and
programmers. Including myself!
The JCSP and CTJ packages provide a complete set of object-oriented design
patterns for threads, synchronising threads AND thread priorities. I have
never seen design patterns for threads, but only some code fragments
explaining threads. Design patterns are recognised by their names (such as
container, observer, factory, etc.). The JCSP and CTJ packages provide
design patterns, named channel and process (incl. Parallel, Alternative
etc.). We need a design pattern book (or web site) explaining these channels
and processes for Java. Otherwise no one takes us serious.
Gerald.
(cut here)
----------------------------------------------------------------------------
---------------------------------------------
import csp.lang.*;
import csp.lang.Process;
import csp.lang.System;
/**
* Program description:
* --------------------
*
* (WriterProcess "A") --a-> (AltingProcess) <-b-- (WriterProcess "B")
*
* StressAlt
* = PAR
* WriterProcess(channel_a, times)
* WriterProcess(channel_b, times)
* AltingProcess(channel_a, channel_b, times*2)
*
* with
*
* WriterProcess(channel,times)
* = FOR i:=0 TO times
* channel ! any
*
* AltingProcess(channel_a,channel_b,times)
* = FOR i:=0 TO times
* ALT
* channel_a ? any
* ReaderProcess(channel_a, "A")
* channel_b ? any
* ReaderProcess(channel_b, "B")
*
* ReaderProcess(channel,name)
* = SEQ
* channel ? any
* print(name)
**/
public class StressAlt implements Process
{
final static int TIMES = 100000;
/** WriterProcess **/
class WriterProcess implements Process
{
ChannelOutput_of_Any channel;
int times;
public WriterProcess(ChannelOutput_of_Any channel, int times)
{
this.channel = channel;
this.times = times;
}
public void run()
{
try
{
for (int i=0; i<times; i++)
channel.write();
}
catch (csp.io.IOException e) { /* exception process */ }
}
}
/** ReaderProcess **/
class ReaderProcess implements Process
{
ChannelInput_of_Any channel;
String name;
public ReaderProcess(ChannelInput_of_Any channel, String name)
{
this.channel = channel;
this.name = name;
}
public void run()
{
try
{
channel.read();
System.out.println("Reader \""+name+"\"");
}
catch (csp.io.IOException e) { /* exception process */ }
}
}
/** AltingProcess **/
class AltingProcess implements Process
{
Process process;
int times;
public AltingProcess(ChannelInput_of_Any channel_a, ChannelInput_of_Any
channel_b, int times)
{
process = new Alternative(new Guard[]
{
new Guard(channel_a, new ReaderProcess(channel_a, "A")),
new Guard(channel_b, new ReaderProcess(channel_b, "B"))
});
this.times = times;
}
public void run()
for (int i=0; i<times; i++)
process.run();
}
}
Process process = null;
public StressAlt()
{
Channel_of_Any channel_a = new Channel_of_Any();
Channel_of_Any channel_b = new Channel_of_Any();
process = new Parallel(new Process[]
{
new AltingProcess(channel_a, channel_b, TIMES*2),
new WriterProcess(channel_a, TIMES),
new WriterProcess(channel_b, TIMES)
});
}
public void run()
{
System.out.println("starting main Process ");
process.run();
}
/**
* Create and start main StressAlt process.
**/
public static void main(String[] args)
{
new StressAlt().run();
}
}