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
import org.taj.ajava.lang.*;
public class Table extends Actor
{
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;
}
private void react_0(Philosopher.IsHungry msg)
{
states[msg.id] = State.HUNGRY;
tryEat(msg.id);
}
public void deliver(Philosopher.IsHungry msg)
{
bufferMessage(new org.taj.ajava.runtime.ActorMessage(msg, 0));
}
protected void react(Philosopher.IsHungry msg)
{
react_0(msg);
}
private void react_1(MoveForks frks)
{
forks[frks.id] = frks.lhf;
forks[right(frks.id)] = frks.rhf;
states[frks.id] = State.THINKING;
tryEat(left(frks.id));
tryEat(right(frks.id));
}
public void deliver(MoveForks frks)
{
bufferMessage(new org.taj.ajava.runtime.ActorMessage(frks, 1));
}
protected void react(MoveForks frks)
{
react_1(frks);
}
private void tryEat(int id)
{
if (states[id] == State.HUNGRY && states[left(id)] != State.EATING && states[right(id)] != State.EATING) {
states[id] = State.EATING;
diners[id].deliver(new MoveForks(id, forks[id], forks[right(id)]));
}
}
protected void processMessage(org.taj.ajava.runtime.ActorMessage msg)
{
switch (msg.reactorId) {
case 0:
{
react_0(((Philosopher.IsHungry)msg.payload));
return;
}
case 1:
{
react_1(((MoveForks)msg.payload));
return;
}
default:
{
super.processMessage(msg);
return;
}
}
}
}