This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

28.11 A SUMMARY OF THE MECHANISM

Here now is the precise description of the concurrency facilities presented in earlier sections. There is no new material in this section, which serves only as reference and may be skipped on first reading. The description consists of four parts: syntax; validity rules; semantics library mechanisms. It extends the sequential O-O mechanisms developed in the preceding chapters. On first reading you may move to "DISCUSSION", 28.12, page 998.

Syntax

The syntactic extension involves just one new keyword, separate.

A declaration of an entity or function, which normally appears as

x: TYPE

may now also be of the form

x: separate TYPE

In addition, a class declaration, which normally begins with one of class C, deferred class C and expanded class C, may now also be of the form: separate class C. In this case C will be called a separate class. It follows from the syntax convention that a class may be at most one of: separated, expanded, deferred. As with expanded and deferred, the property of being separate is not inherited: a class is separate or not according to its own declaration, regardless of its parents' separateness status.

A type is said to be separate if it is either based on a separate class or of the form separate T for some T (in which case it is not an error, although redundant, for T to be separate --- again the same convention as for expanded). An entity or function is separate if its type is separate. An expression is separate if it is either a separate entity or a call to a separate function. A call or creation instruction is separate if its target (an expression) is separate. A precondition clause is separate if it involves a separate call (whose target, because of rules that follow, can only be a formal argument).

Constraints

A Separateness Consistency rule in three parts governs the validity of separate calls:

  • (1) If the source of an attachment (assignment instruction or assignment passing) is separate, its target entity must be separate too.

  • (2) If an actual argument of a separate call is of a reference type, the corresponding formal argument must be declared as separate.

  • (3) If an actual argument of a separate call is of an expanded type, its base class may not include, directly or indirectly, any attribute of a reference type.

There is also a simple consistency rule on types (not given earlier): In a type of the form separate TYPE, the base class of TYPE must be neither deferred nor expanded.

For a separate call to be valid, the target of the call must be a formal argument of the enclosing routine.

Finally, if an assertion contains a function call, any actual argument of that call must, if separate, be a formal argument of the enclosing routine, if any (separate argument rule).

Semantics

Each object is handled by a processor, its handler. If the target t of a creation instruction is non-separate, the newly created object will be handled by the same processor as the creating object. If t is separate, the new object will be allocated to a new processor.

Once it has been created, an object will at any time be in either of two states: free or reserved. It is free if no routine is being executed on it, and no separate client is currently executing a routine that uses as actual argument a separate reference attached to it.

A processor will be in either of three states: idle, busy and suspended. It is busy if it is executing a routine whose target is an object that it handles. It becomes suspended if it attempts an unsuccessful call (defined below) whose target is an object that it handles.

The semantics of calls is affected only if one of more of the elements involved --- target and actual arguments --- are separate. The discussion assumes a call of the general form t.f (..., s, ...) where f is a routine. (If f is an attribute, we will assume for simplicity that it is called through an implicit function returning its value.)

Assume first that one or more of the actual arguments are separate, but the target t is not. The call is executed as part of the execution of a routine on a certain object C_OBJ, which may only be in a busy state at that stage. The basic notion is the following:

--------------------------------------------------------------------------------
Definition: Satisfiable call
In the absence of CONCURRENCY features (described next), a call to a
routine f, executed on behalf of an object C_OBJ, is satisfiable if and only if
its target's handler is idle or suspended, and every separate actual argument
having a non-void value, and hence attached to a separate object A_OBJ,
satisfies the following two conditions:
 S1 ·  A_OBJ is free or reserved by C_OBJ.
 S2 ·  Every separate clause of the precondition of f has value true when
evaluated for A_OBJ and the actual arguments given.
--------------------------------------------------------------------------------

If a processor executes a satisfiable call, the call is said to be successful and proceeds immediately; C_OBJ remains reserved, its processor remains busy state, every A_OBJ becomes reserved, the target remains reserved, the target's handler becomes busy, and it starts executing the routine of the call. When the call terminates, the target's handler returns to its previous state (idle or suspended) and each A_OBJ object returns to its previous state (free or reserved by C_OBJ).

If the call is not satisfiable, it is said to be unsuccessful; C_OBJ enters the suspended state. The call attempt has no immediate effect on its target and actual arguments. If one or more earlier unsuccessful calls are now satisfiable, the processor selects one of them to become successful as just described. The semantics does not specify which satisfiable call to select if there is more than one, but does require the processor to select one.

The final semantic change is the definition of wait by necessity: if a client has started one of more calls on a certain separate object, and it executes on that object a call to a query, that call will only proceed after all the earlier ones have been completed, and any further client operations will wait for the query call to terminate. (We have seen that an optimizing implementation might apply this rule only to queries returning an expanded result.) When waiting for these calls to terminate, the client remains in the "reserved" state.

Library mechanisms

Features of class CONCURRENCY enable us in some cases to consider that condition S1 of the satisfiable call definition holds even if A_OBJ has been reserved by another object (the "holder"), assuming C_OBJ (the "challenger') has called demand or insist; if as a result the call is considered satisfiable, the holder will get an exception. This will only occur if the holder is in a "yielding" state, which it can achieve by calling yield. To go back to the default non-yielding state, the holder can execute retain; the boolean query yielding indicates the current state. The challenger's state is given by the integer query Challenging which may have the value Normal, Demanding or Insisting. To return to the default Normal state the challenger can execute wait_turn. The difference between demand and insist affects what happens if the holder is not yielding: with demand the challenger will get an except

 

Table of Contents Next section