Discussions on Join Concurrency

  1. Chords(or join pattern) are the core of concurrent designs based on Join:

Traditional multi-threaded systems focus on managing threads and their synchronization. However there are many issues with using threads directly as program structuring tools, especially on today's multi-core machines:
Newer concurrency systems are switching to task based designs, such as Java's executor framework and Intel's Threading Building Blocks library:
In Join based applications (Cω and Join), chords play the core role of concurrency design:
synchronization only apply to async<> / synch<> ports which participate in the chords of same joint.
In Join based systems (Join or Cω) there is no explicit thread creation and synchronization or even no explicit task creation and dispatching to executor thread pool. Chords with only async<> ports will implicitly (automatically) create a task for its body and dispatch it to the thread pool of the executor associated with the joint. All concurrency and asynchroncy are defined and created by async<> ports and chords.
  1. Programming model : orchestration of asynchronous activities:
In normal concurrent applications, member variables are used to represent the state of objects and locks are used to coordinate the shared access by multiple threads. In Join based design, async<> ports are used to represent the states of active objects, and chords with these "state-describing" async<> ports can define what behaviour (synch<> / async<> ports) are valid in different object states. Partial specialization of async<> template class reduce the overhead of async<> ports to minimum.
The synchronization design of Java and C# is based on monitor, where a object-wide lock is used to guarantee that only one of "synchronized" methods can be called at anytime and normally the lock is hold during the execution of the method body (a relatively long period).
In Join based systems, when a async<> / synch<> call or message arrives, a object-wide lock is only used to check if any chord is ready to fire (a really short while). More precisely, deciding whether any chord is enabled by a call and, if so, removing the other pending calls from the queues and scheduling the body for execution is an atomic operation. Apart from this atomicity guarantee, however, there is no monitor-like mutual exclusion between chord bodies. So when a chord does fire and during execution of chord body, there is no lock hold anymore. Any mutual exclusion that is required must be programmed explicitly in terms of synchronization conditions in chord headers.
In shared-state model, control flow thru objects: objects are passive, calling thread invoke objects' methods and execute the method body.
In Join based model, active objects are active in that they are responsible for maintaining the integrity of their own state. With async<> ports defining interface, control flow stops at object boundary/interface and data flow thru objects. Using async<> ports to represent object states, chords (join pattern) of these "state-describing" async<> ports and other async<> / synch<> ports can define what behaviour (synch<> / async<> ports) are valid in different object states.
In shared-state model, the interface of concurrent behaviour is still normal objects methods (functions); synchronization among concurrent object behaviours (methods) is indirectly programmed using locks. In Join based model, the interface of concurrent behaviour consist of async<> / synch<> ports, and mostly async<> ports for a loosely coupled interface; and synchronization of concurrent object behaviours (methods) must be explicitly specified as join pattern in chord headers. Normal object methods are mostly used for internal implementation or non concurrency interface.
  1. Inheritance based composition
In child class of "active" classes (classes with joint as base), the following extensions can be performed:
Separating interface and implementation is a basic principle of OO design. In C++, interfaces are normally defined as abstract classes with pure virtual methods which have only headers/signatures and no body defined.

In Join, an async<> / synch<> port is "pure virtual" (has no body) before chord() is called which associates it with a body. So in Join based OO concurrent designs, interfaces can be defined as "abstract" joint based classes which only define async<> / synch<> ports while the definitions of chords and bodies are deferred to children / implementation classes.

There is a difference in error handling: C++ compilers will prevent instantiations of abstract classes, and because Join is implemented as a library, compilers cannot prevent instantiation of "abstract active" classes, the only help are runtime "not_in_chord" exceptions which are thrown when such  objects are used.

Please refer to "Active Objects Tutorial" and " Asynchronous Call and Return Patterns Tutorial" for examples of interface and extension.
In normal C++, a method can be declared "virtual" and can be overriden in child classes (the same header / signature are re-defined with a new body).
In Join, for async / synch ports, their bodies are chords which may be defined with multiple method headers. So in Join, we are talking about chord-overriding and when a chord is overriden, all its method headers are "overriden" in the sense of that they all exhibit new behaviour.
Join supports two kinds of overriding. The chords defined can be overriden with new bodies either thru "virtual" chord body methods or by calling chord_override():
When we define async/synch ports and their chords, the chord "body" method can be declared "virtual". Then in child classes, this chord body can be overriden just as any other virtual methods. When an instance of this child class is used anywhere thru pointers or references to parent class (by calling its async/synch ports), the proper child class chord body method definition will be invoked.
This refers to the capability that chord definitions can be changed by overriding or replacing chord body methods during runtime when code runs. For this purpose, chord_override() is called with the set of async / synch ports (same as the chord to be override) and the new chord body method. The identified chord will replace its chord body with the new method.

Please refer to "Chord Overriding Tutorial" for examples of both static and dynamic overriding.

  1. Aggregation/delegation based composition
Aggregation and delegation promote a kind of software reuse design similar to circuit integration: creating large/outer/containing components (joints) by composing a network of smaller/inner components (joints). Outer/containing components / joints are defined thru the following ways:
Please refer to "Extending by Aggregation and Delegation Tutorial" for a sample.