DisC++: A software library for Object Oriented

2 downloads 0 Views 11KB Size Report
DisC++ (Distributed C++) is a set of C++ libraries for concurrent programming ... ActiveObjects library implements the described object model, that is based on a ...
DisC++: A software library for Object Oriented Concurrent and Distributed Programming Federico Bergenti, Agostino Poggi, Giovanni Rimassa and Matteo Somacher Dipartimento di Ingegneria dell’Informazione Università di Parma, Parco Area delle Scienze, 181A, 43100 Parma, Italy e-mail: { Bergenti, Poggi, Rimassa, Somacher } @ce.unipr.it Tel: +39 0521 905712 Fax: +39 0521 905723 Introduction DisC++ (Distributed C++) is a set of C++ libraries for concurrent programming that provides a comprehensive framework particularly suitable for coarse-grained distributed applications development. It can be considered a good alternative to classical distributed programming libraries, such as PVM and MPI, to develop distributed applications. Code reuse is stimulated by the adopted object model, which provides a solution to the inheritance anomaly problem [1], trying to minimize the redefinition of inherited methods. ActiveObjects library implements the described object model, that is based on a special set of method definitions, allowing method bodies to be defined independently by their synchronization constraints. In fact, two synchronization constraints are defined for each method in order to decouple method body definition from problem-based synchronization requirements. RemoteObjects library supports object distribution on different address spaces by means of CORBA, allowing for the implementation of applications built with different Object-Oriented languages.

1. Library description ActiveObjects library is based on a class of objects, that we call active objects, which are composed by the following parts: a set of state variables, a set of ordinary, non concurrent, methods and a set of interface methods. Interface methods describe what an active object can export to the rest of the application and separate their code in a body, a guard and a transition clause to cope with inheritance anomaly [2]. The body part is the code performing the task of the method and directly accessing object internal state, whereas guard and transitions parts declare object synchronization constraints. The guard part is a boolean predicate without side effects on object state, depending only on instance variables values and method arguments, while the transitions part is a set of pairs made by aboolean expression and two lists of interface methods. The guard states a precondition which must be true in order to execute the interface method, so a guard predicate is evaluated before method body execution: if the predicate turns to false, the execution is suspended until the object state changes. The transitions part allows an interface method to affect other methods execution without using dummy state variables, thereby completelydecoupling computation and synchronization constraints. Transitions predicate is evaluated after method body execution: provided the predicate is true then every interface method of the first list (called the disable list) becomes not-executable until further enabled, while every interface method of the second list (called the enable list) remains executable. An interface method remains enabled or disabled until a subsequent method transition changes its state. Following the described procedure, each interface method can disable and/or enable all the methods of the active object. Guards and transition clauses determine which method is executable and which is not: a request for an interface method is served if and only if it is enabled and its guard is true. Interface methods are divided into readerMethods, that can be executed in parallel, and writerMethod, that has to be executed in mutual exclusion. Each call to an active object method starts a client/server interaction that needs the synchronization rules to be defined. The library supports three different rendez-vous policies: synchronous, deferred and asynchronous calls. Besides it provides asynchronous method invocations with callback [3] allowing to

execute a function defined by the client at the end of the method delegating to the server the synchronization control. In order to support object distribution across different address spaces, RemoteObjects library introduces proxy objects[4]. A proxy object provides a set of proxy methods linked to the corresponding set of interface methods on the server side. If a programmer wants to use active objects in distributed environments, she has to register the needed active object on a class named OA (Object Adapter) and to create an instance of class proxy object on the client side, then she can invoke the proxy methods. Proxy objects provides the same rendez-vous policies offered by active objects. On the server side the active object dispatches both local and remote method invocations following the appropriate synchronization constraints. The library provides a run-time mapping between CORBA types and C++ types and uses the CORBA dynamic interfaces (DII and DSI) to link proxy objects to active objects [5]. On the server side, once the active object is connected to the ORB (Object Request Broker) it is also a CORBA object so the programmer could invoke its methods building an IDL interface.

2. Library design and implementation Current operating systems support intra-application concurrency by means of the multithreading paradigm. Thus an entire set of API is provided in order to handle thread creation, scheduling and synchronization by means of mutexes, counting semaphores and condition variables. All those interfaces are mainly composed by a set of C functions and therefore they are less abstract than usual OO libraries and frameworks; besides, each operating system implements its own set of multithreading services, roughly equivalent with the competitors’except for names and conventions. In order to bridge those incompatibilities, our library has a two-layers design: a set of simple object-oriented wrappers provide a platform-independent thread layer, while, at a higher level, active-object layer is built ontop of the thread-layer services. The thread layer is meant to encapsulate platform-specific multithreading support into a portable, object-oriented group of classes that can be used as building blocks for more complex abstractions. Nevertheless, those low-level objects can also be used by themselves or even to build frameworks based upon different object models than ours. In order to ease porting, only four classes in this layer contain some operating-system specific code: these are classes thread, mutex, semaphore and conditionVariable. The thread layer provides also memory management for threads using the handle/body programming idiom and a ThreadPool class to allow reusing and optimizing threads. The active and remote objects layers use thread classes to implement active and proxy object classes. The library adopts the following concurrency model. Synchronous method calls are executed by the calling thread, so no context switch occurs during the critical path of the call. Deferred and asynchronous calls are dealt with differently, according to whether they are reader or writer. A single thread is shared among all the writer methods, whereas a dynamic thread pool provides threads to all the reader methods. Currently, a working implementation of our library uses POSIX 1003.1c threads and runs under Linux operating system; the porting to other operating systems involves only four thread-layer classes. The library source code conforms to draft ANSI/ISO C++, using the Standard Template Library (STL) for internal data structures and ISO compliant boolean and string types, besides new type casts. Since both GNU cc and all major compiler vendors support the bigger part of ISO C++ language features and the C++ Standard Library is now approaching stability, there should be no portability problems related to specific C++ dialect or compiler. DisC++ library uses POSIX threads and synchronization objects to achieve concurrency; every active object has a built-in monitor for readers and writers made by a mutex associated with various condition variables, one for each interface method. Method slave threads access the monitor through their condition variable, but a couple of lock()/unlock() methods is provided for ordinary methods to enforce mutual exclusion. Since users must write a guard predicate and a body for every interface method, our library must call user specified code. In an earlier version we employed virtual functions, but this required a large amount of subclassing. We switched to «pointer to member functions», obtaining per-instance code and avoiding subclassing entirely: now each interface method has two private pointers to its guard predicate and body, assigned during construction.

3. Discussion DisC++ provides classes with two level of abstraction. This allows programmers to use simple constructs when needed and to develop applications without handling low level concurrency and distribution constraints

during the software life-cycle. It provides also a Location Forward mechanism for increased flexibility in object binding. DisC++ communications rely on CORBA, so they grant interoperability with many structured and object oriented languages. Moreover, since DisC++ uses an implicit message passing model that achieves location transparency and threads to support concurrency, gives high level abstractions to the distributed systems programmer. On the other hand, a library such as MPI binds just on C and FORTRAN77, requires the programmers to deal with explicit message passing and provides concurrency through multi-processing. Next version of DisC++ will also run on Win32 systems and will include a persistent object library to save the object state and to allow applications to pass objects by value.

4. Acknowledgements The work has been partially supported by a grant of the European Community (Tender to III/97/31 Lot 5 Cluster Computing for data Intensive Application).

5. References [1] S. Matsuoka and A. Yonezawaka. Research Directions in Concurrent Object-Oriented Programming, pagg.107-160. The MIT Press, 1993. [2] A. Poggi and G. Rimassa. An efficient and flexible C++ library for concurrent programming. Software Practice & Esperience, 28(13):1437-1463, 1998. [3] D.C. Schmidt and S. Vinosky. Distribuited Callbacks and Decoupled Communication in CORBA. SIGS C++ report magazine. October 1996. [4] E. Gamma, R. Helm, R. Johnson and J. Vlissides. Design Patterns: Element of Reusable Object Oriented Software. Addison Wesley, 1995. [5] M. Henning and S. Vinosky. Advanced CORBA Programming with C++.Addison Wesley, 1999.

Suggest Documents