Next Previous Up Top

5 Examples

5.3 Active Remote Objects, Asynchronous Calls, and Transparent Futures

5.3.1 - Process
5.3.2 - Using Remote, Asynchronous, Active Objects
5.3.3 - Programming the Library

5.3 Active Remote Objects, Asynchronous Calls, and Transparent Futures

This third example of europa standard illustrates how to build, as a library, active objects with a remote instantiation, e.g. on a cluster of machines. The framework also achieves asynchronous calls with transparent futures semantics on the results of those calls, and automatic (un)marshalling of parameters. This particular library implements a mimd model with:

The wait-by-necessity (automatic and transparent futures) allows the parallelization of object-oriented sequential system in a data-flow manner.

The programming of this Level 1 library is based on the introduction of a Process class. All objects which are an instance of a class which publicly inherits from the Process class are processes (active object = process). Passive objects (i.e. objects which are not active) belong at run-time to a process object, thus giving a distributed structure of active objects encapsulating passive objects.

A communication between active objects is simply programmed as an asynchronous member function call:

p->foo( parameters );
res = p->bar ( parameters );

Such a function calls between active objects (processes) is implicitly (by default) asynchronous, thus allowing and encouraging parallel execution of objects (although a synchronous method call is also supplied but must be stated explicitly in the function call itself or in the process definition). The wait-by-necessity adds automatically the synchronizations when needed.

The semantics of communication between processes is a copy semantics for passive objects: all parameters are automatically transmitted by copy from one process to another. Of course, active objects are subject to a reference semantics: all processes are transmitted by reference from one process to another. As a consequence, shared objects (i.e. passive objects which are shared between active objects) are not allowed as such. The implication of this is that any passive object which is to be shared between several active objects must be made an instance of a class derived from process. This is simply achieved by inheriting from the process class (which also provides an automatic fifo synchronization).

5.3.1 Process

Let us start this time with the reified class Process that represents a process class from which library users inherit in order to instantiate remote active objects.

namespace EC
	class Process: public EC_Reflect, public Request_line
		// A reified class.
		// Inheriting from Request_line brings all the service routines
		// and the pending request management.
		void* operator new (size_t s, Mapping m);
		// Mapping allows to control on what machine the allocation
		// takes place
		void Live ()
			// Behaviour of the active object: default is a FIFO service
			// Called by the Process constructor

		Process ()
		{ // Constructor
			Live ();

		Process_P* ec_proxy();

5.3.2 Using Remote, Asynchronous, Active Objects

Using the class C of the echo example, the user of the library can get asynchronous remote C as follows:

class ARC: public C, public Process
	ARC(P1 pl): C(pl), Process () {}
	ARC(P1 p2): C(p2), Process () {}

The class ARC now features remote instantiation, and asynchronous calls on its member function in a transparent manner:

void main()
	P1 pl;
	Res* vl,v2,v3;
	Mapping map;

	ARC* arcl = ec_new ((map("'')), ARC,(pl));
	ARC* arc2 = ec_new ((map("'')), ARC,(pl));

	vl = arcl->vfoo(...); // Asynchronous remote calls
	v2 = arc2->vfoo(...);
	v3 = arcl->foo (...);

	vl->bar(); // Automatically triggers a wait until the
	v2->bar(); // value is actually returned from a thread
	// The only constraint being that function bar has to be virtual

	// Remote objects can be pass as parameters to remote
	// calls, providing dynamic topology.

	C* c;
	c = arcl; // For the sake of reuse, polymorphic assignment is
	// possible between local entities and remote objects

	. . .

	vl = c->vfoo(...); // Asynchronous remote call

Of course, in that case again the user can check the results availibility with the technique presented for the previous example.

5.3.3 Programming the Library

In order to program this library, the proxy for Process is defined as follows:

namespace EC
	class Process_P: public EC_Proxy
		// Constructor
		Process_P (Mapping map, EC_Class cl, EC_Call* c)
			robj=new_robj_id (map);
			// Interpret the mapping value,
			// and returns a remote object id: obj ID, Machine ID
			remote_create (robj,cl,c);
			// Actual remote creation of the reified object
			// of type cl, constructor represented by c will
			// be called.
			// Usually executed synchronously
		// Call reification
		void ec_reify (EC_Call* c)
			// Get a new request id
			req_id= new_req_id();
			// Future creation
			EC_Class rt = c->mb()->return_type(); // Get result type
			Future_P* pr = new Future_P(); // Build a future proxy
			EC_Any fut = rt->new_reified_object(pr); // reified future object
			// Keep track of the correspondence between future and
			// request id for later update when result will be received
			enqueue (fut,req_id);
			// Remote non-bloking call
			remote_send (robj,req_id,flat(c));
			// The reified call is sent to the remote object.
			// Effective parameters held in c are marshalled by the flat
			// function: call flat on the object if user-defined, otherwise
			// calls a generic flat.
			// The result will come back together with the request id,
			// such that the corresponding future will be updated with the result

		Remote robj; // Remote object reference: network and transport aware

The classes Future and Future_P of the previous example are reused with no change.

Copyright 1997 EUROPA WG

Last updated: 26 Nov 1997