Mombu the Programming Forum

Go Back   Mombu the Programming Forum > Programming > Mandala project: dynamic concurrent and distributed programming without threads
User Name
Password
REGISTER NOW! Mark Forums Read




Reply
1 5th October 11:44
eipi
External User
 
Posts: 1
Default Mandala project: dynamic concurrent and distributed programming without threads



The open source project (LGPL license) Mandala (http://mandala.sf.net) provides
a new model to deal with both concurrent and distributed programming. Moreover,


invocation paradigm to asynchronous (and potentially remote) method invocation.

Whereas threads are a good entities for concurrent programming in imperative
languages (such as C), I believe they are not good ones (and especially Java
threads) for concurrent programming in object oriented languages.

For example, in Java, Thread requires a run() method to be defined which
represents the thread behavior. Invoking this method produce the same result --
from a Java newbie point a view -- as invoking start(). Is is hard to
understand that a Java Thread instance is not the *real* thread but only a
(bad?) representation of it. Many problems with Java Threads have already been
mentioned in the literature (stop(), suspend()/resume(), scheduling and
priorities which are OS dependent (no more green threads since the JDK 1.3)).

Last but not least, implementing concurrency using threads leads to a direct
dependency between the asynchronism functionality and the actual
implementation of it.

For example, consider the following server code:


ServerSocket ss = new ServerSocket();
while(true) {
Socket socket = serverSocket.accept();
new Thread() {
public void run() {
serve(socket);
}
}.start();
}

The problem is that the asynchronism is tied to the implementation, here, one
thread per call. For performance reasons, it might be better to use a threads
pool...

Another example, suppose you want asynchronous input/output (of course, you may
use the new Java IO package -- available since the JDK 1.4 -- for this purpose
, but this example serves my speech):

The "natural" synchronous code is:

InputStream is = ...; OutputStream os = ...;
byte[] b = ...; int n = ...;
while((n = is.read(b)) != -1) {
os.write(b, 0, n);
}

which leads when using threads *naively* to something like:

while((n = is.read(b)) != -1) {
new Thread() {
public void run() {
os.write(b, 0, n);
}
}.start();
}

which is erroneous as you may have guessed: the byte buffer 'b' is
shared across multiple threads. Whereas a 'synchronized' section
solves the problem it leads to really poor performance and breaks the
concurrency searched for: writers write while readers read.


Asynchronism in Mandala is based on its RAMI (Reflective Asynchronous Method
Invocation) package which provides asynchronous method invocations using the
asynchronous reference concept. Asynchronous references are the standard Java
synchronous references extension to the asynchronous world: an asynchronous
reference on an object allows any public method of this object to be invoked
asynchronously.

Asynchronous proxy are "sugar syntactic" mirror classes of standard classes
which provides transparency in asynchronous (and potentially remote, see below)
method invocation. An asynchronous proxy uses an asynchronous reference for the
actual asynchronous method invocation mechanism implementation.

Using asynchronous references in the server example above leads to something
like:

ServerSocket ss = new ServerSocket();

// Creates an asynchronous proxy on a 'Service' instance
// which contains the serve() "business" method
jaya.Service service = new jaya.Service();
while(true) {
Socket socket = serverSocket.accept();
service.rami_serve(socket); // asynchronous call
}


The advantages are the following:

1) the asynchronous functionality is customizable (tied to the
asynchronous reference) and does not appear in the code; the creator of
the asynchronous proxy on the 'Service' instance has the responsibility
of the asynchronous semantic attached to its object. Two semantics are
defined:

- concurrent semantic: asynchronous method invocations may run
concurrently on the same object. This semantic has currently
two implementations:

* a thread per calls implementation,
* a threads pool implementation;

- single-threaded semantic: asynchronous method invocations are
never run concurrently on the same object. This semantic allows
non-thread-safe objects to be used asynchronously anyhow. Two
implementations is provided:

* a FIFO implementation where methods are run in the
order they are invoked,

* a random implementation where methods are run in a
random order.

In the example above, the default semantic is used because no semantic
are defined.

If a threads pool implementation is required, the instantiation must
be:

AsynchronousSemanticFactory asf = new ThreadPooledASFactory();
jaya.Service = new jaya.Service(asf);

2) Code simplification: no more thread in the code, everything is
method invocation (either synchronous or asynchronous). I believe
programmers must write their code using only method invocation which
extends naturally to remote method invocation as proved by the RMI
success. Similarly, concurrent programming may use asynchronous method
invocations instead of dealing directly with threads.


Using asynchronous references in the asynchronous input/output example above
leads to:

InputStream is = ...; OutputStream os = ...;

// A FIFO semantic is required!
AsynchronousSemanticFactory asf = new FifoASfactory();

// Gets an asynchronous proxy on the 'os' instance
jaya.java.io.OuputStream ramios = (jaya.java.io.OuputStream)
Framework.getSemiTransparentAsynchronousProxy(os, asf);

int n = ...; FutureClient future;
while(true) {
byte[] b = new byte[n];
n = is.read(b);
if (n == -1) break;
future = ramios.rami_write(b, 0, n);
}

doSomething(); // During the output...

// Using a FIFO semantic guarantees that everything is written
// in order. Hence, when the last asynchronous method invocation
// has terminated, we are sure everything has been done.
future.waitUntilDone();

And, as you see, the problem is solved by using a FIFO asynchronous
semantic and by the creation of a new byte buffer for each
read()/write().

The use of asynchronous method invocation is quite natural and prevent
developers to deal with threads related problems such as scheduling, priorities
and canceling (stopping(), interrupting()). For example, canceling an
asynchronous operation is not performed same by a thread per call
implementation (where you just call interrupt() on the target thread) than by a
threads pool implementation call scheme (interrupt() is erroneous!). In
Mandala, canceling an asynchronous method invocation is just a matter of
invoking the method 'cancel()' on the 'Future' object returned. The actual
implementation does all the magic for you. All this asynchronous implementation
dependent issues are handled by the asynchronous reference implementation used.

Naturally, Mandala extends asynchronous method invocation to asynchronous
remote method invocation using its JACOb (Java Active Container of Objects)
package which relies on RAMI and on the active container concept. Any objects
can become remote and used asynchronously. No more interface to implements
(like in RMI or in Corba), no class to extend: only business code in your
objects! Hence, your remote objects do not depend on any particular technology.

JACOb uses the "active container" concept through the 'ActiveMap'
implementation. The concept is very simple. An active container is just a map
which provides a call() method to invoke method on its stored objects.

Consider the example below:

// Use JNDI to get a remote active map reference

ActiveMap activeMap = null;

String URL = "rmi://host/RMIActiveMap"; // may be LDAP

// JNDI part
try{
javax.naming.InitialContext context =
new javax.naming.InitialContext();
activeMap = (RemoteActiveMap) context.lookup(URL);
}catch(NamingException ne) {
...
}


// A library returns an object I want to use remotely
java.math.BigInteger bi = library.foo();

// Get a global unique key
Object key = StoredObjectReference.getGlobalUniqueKey();

// Insert 'bi' in the remote active map
activeMap.put(key, bi);

// Get a stored object reference on it
StoredObjectReference sor =
StoredObjectReference.getInstance(activeMap, key);

// Get an asynchronous proxy on this stored object
jaya.java.math.BigInteger i =
jaya.java.math.BigInteger.getInstance(sor);

// 'i' is now a proxy on the stored object 'bi' in 'activeMap'
assert sor == (StoredObjectReference) i.getAsychronousReference();
assert activeMap.containsKey(sor.getKey());

// Our 'BigInteger' is remote whereas it has not be designed for it!
assert activeMap instanceof RemoteActiveMap;

// Invoke a method remotely and asynchronously
FutureClient future = i.isProbablePrime(CERTAINTY);

doSomethingElse();

try{
boolean isPrime = future.waitForResult();
}catch(TransportException te) {
// Handle if necessary
}

As you see, 'ActiveMap' extends the 'java.util.Map' interface - nothing to
learn! 'RemoteActiveMap' is just an 'ActiveMap' remotely accessible. Then, we
can insert an object into the active map (here a 'java.math.BigDecimal'
instance returned by a library) using the 'put()' method. And then, the stored
object is automatically remotely accessible through the active container it
resides in! Asynchronous remote method invocation on stored objects are done
using asynchronous proxies of the RAMI package. Note that if you are the
creator of the stored object, things are simpler:

// Create a stored object transparently

// (A new key is automatically created)
jaya.java.math.BigInteger i =
new jaya.java.math.BigInteger("1234567890",
new SORFactory(activeMap));

// Invoke a method remotely and asynchronously
FutureClient future = i.isProbablePrime(CERTAINTY);

doSomethingElse();

try{
boolean isPrime = future.waitForResult();
}catch(TransportException te) {
// Handle if necessary
}

Features of the Mandala RAMI packages are:

- Asynchronous references: extension of standard Java synchronous
reference (provides the '==' semantic);

- Asynchronous method invocations using future objects and/or callbacks
(event-driven programming) mechanism;

- Separation of asynchronous semantics and their implementations
(concurrent versus single-threaded semantic)

Features of the Mandala JACOb packages are:

- Based on a formal model: the active container concept;

- Simple API: ActiveMap extends Map;

- Multi-protocol: currently RMI, TCP, UDP are provided;

- Asynchronous remote method invocations using StoredObjectReference
which is an asynchronous reference implementation;

- Remote exception handling based on global listeners: this allows
"only business code in remote method invocation" paradigm or the
traditional per-method remote exception handling (RMI-like) to be
implemented;

Features of the whole Mandala projects:

- Designed by interfaces: anyone may provide its own implementation of
asynchronous semantic, asynchronous references, ActiveMap, protocol,
etc.

- Extensive use of design pattern -- maybe too extensive!

- Designed with unitary test (JUnit)

- Build with the standard Apache-ant build tool

- Well documented: Javadoc and PDF (LaTEX generated) User's guide

Lacks:

- A good web site: I'm not a web designer! Christina -- the web
designer shortly enrolled -- will deliver a more complete and nicer web
site soon.


- A lot of things have to be done (see the TODO list in the root
directory).


As I'm alone in this project I would like some help (object oriented designer,
developers, tester, ...). Furthermore, I'm very interested in software
engineering and I would like experiment the distributed extreme programming
agile method. Anyone interested? Join!


Any remark, comment or suggestion would be greatly appreciated!

Thanks.

eipi.

The Mandala project: http://mandala.sf.net

--
No one equals eipi : -1 = e^(i.Pi)
  Reply With Quote


 


Reply


Thread Tools
Display Modes




666