Copyright Tristan Aubrey-Jones May 2008.
Abstract: A project investigating and developing an implicitly concurrent programming language, based on a metaphor taken from the physical world is reported. Uses a programming paradigm where programs consist of systems of autonomous agents, or active objects which communicate via message passing. A language enhancing Java with actors and linear types is presented. Example programs are written, compiled, and executed to evaluate the usefulness of the language. The language found to provide a familiar notation for implicit parallelism, and a compelling new model for concurrency, combining the performance of shared variables with the elegance of message passing.
Introductory Slides (PDF),
Report (PDF),
ActiveJava compiler prototype (ajavac),
ActiveJava runtime library (ajava_lang).
Examples:
calc - pocket calculator actor program dining - dining philosophers actor program (never deadlocks) sort - parallel quicksort implementation ("SortBenchmark" sorts 10,000 random integers using actors, java threads, and sequentially and compares)To compile examples use:
compile.bat ./calc compile.bat ./sort compile.bat ./diningTo run examples use:
run ./calc Main run ./dining Main run ./dining Main fast run ./sort Main run ./sort SortingBenchmark
public aclass Table {
private Clock clk;
private int numPlaces;
private Fork[] forks;
private Philosopher[] diners;
private int[] states;
public Table(Clock clk, int numPlaces) {
this.clk = clk;
this.numPlaces = numPlaces;
this.forks = new Fork[numPlaces];
this.diners = new Philosopher[numPlaces];
this.states = new int[numPlaces];
createPlace(numPlaces-1);
}
private void createPlace(int index) {
forks[index] = new Fork(index);
diners[index] = new Philosopher(this, index);
clk.subscribe(diners[index]);
states[index] = State.THINKING;
if (index > 0) createPlace(index-1);
}
private int left(int id) {
id--;
if (id < 0) id += numPlaces;
return id;
}
private int right(int id) {
id++;
if (id >= numPlaces) id -= numPlaces;
return id;
}
// when a philosopher becomes hungry, updates its
// state, and tries to eat
public react (Philosopher.IsHungry msg) {
// update state
states[msg.id] = State.HUNGRY;
// try and eat
tryEat(msg.id);
}
// when receives some forks from a philosopher
// records the fact it is thinking, and tries
// serve its neighbours
public react (MoveForks frks) {
// return forks
forks[frks.id] <-- frks.lhf;
forks[right(frks.id)] <-- frks.rhf;
states[frks.id] = State.THINKING;
// try left and right
tryEat(left(frks.id));
tryEat(right(frks.id));
}
// if the philosopher is hungry, and neither
// neighbour is eating, then pass it its forks.
private void tryEat(int id) {
// if hungry, and left not eat, and right not eating
if (states[id] == State.HUNGRY &&
states[left(id)] != State.EATING &&
states[right(id)] != State.EATING)
{
// move forks to the philosopher
states[id] = State.EATING;
diners[id] <-- new MoveForks(id, forks[id], forks[right(id)]);
// remember: forks[id] and forks[right] are destructive reads
// as are linear objects
}
}
}