Author: Maurice Herlihy

# Aleph Toolkit Tutorial

This document is an introduction to using the Aleph Toolkit, a collection of Javatm packages implementing a simple, platform-independent distributed shared object system. It does not describe the mechanics of how to install or run the toolkit, which may vary from site to site. For that kind of information, please see the User's Guide.

A toolkit client is a distributed program that runs on a number of logical processors, called Processing Elements (PEs). Each PE is a Java Virtual Machine, with its own address space. PEs communicate in various ways:

- One PE can create and start a remote thread at another.
- PEs can share global objects.
- PEs can synchronize by Event objects which support reliable ordered multicast.

## Hello World

To illustrate how remote threads work, we will construct a `Hello` class implementing the customary Hello World application. The first step is to make the Aleph API available to the program:

`import aleph.*;`
`public class Hello {`

The remote thread that will execute at each PE is defined as a static inner class:

`static class HelloThread extends RemoteThread {`
`public void run() {`
`System.out.println("Hello World from PE " + PE.thisPE() +`
`" of " + PE.numPEs());`
`}`
`}`

Every remote thread must extend the abstract class `aleph.RemoteThread.` Like regular Java threads (`java.lang.Thread)`, the class must provide a `public void run()` method to be called when the thread is started. The `aleph.PE` class manages processing elements (PEs). Here, `PE.thisPE()` returns the `PE` where the program is running, and `PE.numPEs()` returns the total number of PEs.

As usual for Java programs, your class must include a method with signature

`public static void main(String[] args) {`

to be called when your program starts. Here, this method starts by creating an instance of a remote thread object.

`HelloThread thread = new HelloThread();`

As with regular threads, a remote thread does not start executing until it is explicitly started. Next, the program creates an `aleph.Join` object to allow the caller to wait until the remote threads have completed:

`Join join = new Join();`

The method then executes a `for` loop , which uses `PE.allPEs()` to enumerate all PEs. The loop body starts an instance of the remote thread at each PE. (Unlike `java.lang.Thread`, it is possible to start a single `RemoteThread` instance multiple times.)

`for (Enumeration e = PE.allPEs(); e.hasMoreElements(); )`
`thread.start((PE) e.nextElement(), join);`

Finally, the caller waits for all remote threads to finish.

`join.waitFor();`

The result of running this program should look something like this:

`Hello world from PE[0] of 4`
`Hello world from PE[1] of 4`
`Hello world from PE[2] of 4`
`Hello world from PE[3] of 4`

Another way to write this program is to use a `RemoteFunction` , which is a remote thread that returns a result (essentially a remote procedure call). Here, the remote function must define a `run` method that returns a value:

`static class HelloThread extends RemoteFunction{`
`public Object run() {`
`return "Hello world from " + PE.thisPE() + " of " + PE.numPEs();`
`}`

The caller collects the responses by iterating over a `join` object:

`while(join.hasMoreElements())`
`System.out.println((String) join.nextElement());`

## Global Objects

PEs can also share data structures called global objects, defined by the `GlobalObject` interface. To illustrate how global objects work, we will construct a `Counter` class implementing a simple shared counter application. A global object is a container for a regular Java object. In this case, the counter is defined as a class:

`public class Counter implements java.io.Serializable {`
`public long value;`

All objects shared by PEs must implement `java.io.Serializable`. The `main` method for the class simply encapsulates the counter in a `GlobalObject` as follows:

`GlobalObject global = new GlobalObject(new Counter());`

This object is passed as an argument to the constructor for the user's threads:

`public UserThread(GlobalObject global) {`

Each user thread access the counter by opening the global object in ``write'' mode:

`Counter counter = (Counter) global.open("w");`

The cast is necessary because `open` returns an object of class `java.lang.object,` and the ```w`'' indicates that the object is to be accessed in write mode. Currently supported modes are read `"r"` and write `"w"`. In read mode, the object is up-to-date, but should not be modified. In write mode, the object is up-to-date, and may be modified. Note that thread-level synchronization may be needed to support concurrent write and copy accesses.

Once the counter is open, it can be modified and released.

`Counter.value++;`
`global.release();`

The Aleph toolkit also supports transactions running at a single PE. Here is a simple example:

`Transaction t = new Transaction();`
`Counter counter = (Counter) global.open(t, "w");`
`if (t.commit())`
`System.out.println("Counter incremented");`
`else`
`System.out.println("Counter increment failed");`

For the time being, transactions must execute entirely within a single PE.

# Events

Events provide a simple and flexible way for threads in different PEs to synchronize. An `Event` object is a kind of global object: it can be shared among multiple PEs.
When a thread calls an `Event` object's `signal` method, then that signal is (conceptually, at least) broadcast to all other PEs, together with a copy of the (optional) argument to the call.

If a PE wants to be notified that an event has been signaled, it registers a Listener object with that event. Just as in the Abstract Window Toolkit (awt), the listener is a dummy object that provides a `void actionPerformed(Object object)` method that is called when the event is signaled. The argument to the method is the argument to signal, or `null` if there was no argument. Signals are delivered in order, and each signal is delivered only once to each PE.

For an example of how to use events, see the implementation of the Barrier class.