-- is created; note that it is necessary to use a -- function as a task type cannot be used directly -- within its own body to create a further task instance Next_Sieve := Get_New_Sieve(New_Buf’Access);
New_Buf.Put(Num);
loop
B.Get(Num);
if Num rem Prime /= 0 then New_Buf.Put(Num);
end if;
end loop;
end Sieve;
Note that this program will not terminate correctly. One way of programming termination, in this example, is to pass a ‘close-down’ token such as zero down the pipeline. Other methods will be considered in later chapters.
4.2 Task activation, execution, finalisation and termination A task is said to becreated by its elaboration.
Definitions: The execution of a task object has three main active phases:
(1) Activation– the elaboration of the declarative part, if any, of the task body (any local variables in the body of the task are created and initialised during activation).
(2) Normal execution – the execution of the statements within the body of the task.
(3) Finalisation– the execution of any finalisation code associ- ated with any objects in its declarative part.
A task, in general, indicates its willingness to begin finalisation by executing its
‘end’ statement. A task may also begin its finalisation as a result of an unhan- dled exception, or by executing a select statement with a terminate alternative (see Section 6.6), or by being aborted (see Section 9.2).
Definition: A finished task is called completed or terminated depending on whether it has any active dependants (see Section 4.3).
4.2.1 Task activation
For static tasks, activation starts immediately after the complete elaboration of the declarative part in which they are defined:
declare
task type T_Type;
task A; -- task A is created when this -- declaration is elaborated B, C : T_Type; -- tasks B and C are created when
-- these declarations are elaborated I, J : Integer;
task body A is ...
task body T_Type is ...
begin
-- All tasks created in the above declarative region -- begin to activate as soon as the elaborations of -- the declarative region have finished.
-- Sequence of statements: the first statement is executed -- once all tasks have finished their activation.
end;
Important notes:
The following points on task activation should be noted.
• All static tasks created within a single declarative region begin their activations immediately the region has completed elaboration (i.e., after ‘begin’ but before any following statements).
• The first statement following the declarative region is not executed until all tasks have finished their activation.
• Following activation, the execution of a task object is defined by the appropriate task body.
• A task need not wait for the activation of other concurrently cre- ated tasks before executing its body.
• A task may attempt to communicate with another task which, al- though created, has not yet been activated. The calling task will be delayed until the communication can take place.
If a task object is declared in a package specification, then it commences its execu- tion after the elaboration of the declarative part of the package body:
package Client is task Agent;
end Client;
package body Client is
task body Agent is separate;
begin
-- Agent starts executing before 1st statement -- of this sequence begins executing.
...
end Client;
4.2 Task activation, execution, finalisation and termination 67 If the package does not contain initialisation code, then it acts as if there is a
‘null’ sequence.
Important notes:
Dynamic tasks
(1) are activated immediately after the evaluation of the allocator (thenewoperator) that created them, and
(2) the task, which executed the statement responsible for their creation, is blocked until the tasks created have finished their activation.
The following stylised code illustrates the above points:
declare
-- a declarative region executed (say) by task Parent task type T_Type;
type Prt_T_Type is access T_Type;
A1 : T_Type; -- creation of A1 A2 : T_Type; -- creation of A2 task body T_Type is ...
begin -- activation of A1, A2 declare
B : T_Type; -- creation of B C : Prt_T_Type := new T_Type;
-- creation, activation of C.all D : Prt_T_Type;
begin -- activation of B
D := new T_Type; -- creation, activation of D.all end;
end;
In the above example, the tasks are created and activated by theParenttask in the following order:
(1) TaskA1is created.
(2) TaskA2is created.
(3) TasksA1andA2are activated concurrently and theParentwaits for them to finish their activation.
(4) Assuming a successful activation: A1, A2and Parent proceed concur- rently.
(5) Parentcreates taskB.
(6) Parentcreates and activates taskC.all, and waits for it to finish activa- tion.
(7) Parentactivates taskB, and waits for it to finish activation.
(8) Parentcreates and activates taskD.all, and waits for it to finish activa- tion.
Program errors during task creation and activation
Program errors can lead to exceptions being raised during these initial phases of a task’s existence. If an exception is raised in the elaboration of a declarative part, then any task created during that elaboration becomes terminated and is never activated. For example if in the following, Initial Value is a function that returns an integer value, then there is a possibility that it will return a value outside Data Range. This would result in the exception Constraint Error being raised in a declarative part which also declares a task. In this case the Agent task is never activated. As the exception is raised on elaboration of the declarative block, it cannot be handled within that block but must be caught at an outer level.
declare -- outer block ...
begin
declare -- inner block task Agent;
subtype Data_Range is Integer range 1 .. 10;
Data_Object : Data_Range := Initial_Value;
task body Agent is ...
begin ...
exception
-- any exception handlers here will only catch
-- exceptions raised during the ‘begin .. exception’, -- and not those raised in the elaboration
-- of the declarative part end;
exception
when Constraint_Error =>
-- recovery routine for exception -- raised in the inner block end;
If an exception is raised during a task’s activation, then the task itself cannot handle the exception. The task is prevented from executing its body and hence becomes completed or terminated. If any objects have already been created, then they must be finalised (see Section 4.3). As the task itself cannot handle the ex- ception, the language model requires the parent (creator) task or scope to deal with the situation: the predefined exceptionTasking Erroris raised. In the case of dynamic task creation, the exception is raised after the statement that issued the allocator call. However, if the call is in a declarative part (as part of the initial- isation of an object), the declarative part fails and the exception is raised in the surrounding block (or calling subprogram).
4.2 Task activation, execution, finalisation and termination 69 For static task creation, the exception is raised prior to the execution of the first statement of the declarative block. This exception is raised after all created tasks have finished their activation (whether successfully or not) and it is raised at most once. For tasks created statically during a declarative part, the associated exception handler must be at the outermost level of the declarative block; therefore little direct error recovery is possible. The attributeCallable can, however, at least be used to identify the rogue task (assuming the well-behaved tasks have not terminated correctly before the parent executes its exception handler):
declare
task Child_1;
task Child_2;
task body Child_1 is ...
task body Child_2 is ...
begin null;
exception
when Tasking_Error =>
if not Child_1’Callable then
Put("Task Child_1 failed during activation");
end if;
if not Child_2’Callable then
Put("Task Child_2 failed during activation");
end if;
if Child_1’Callable and Child_2’Callable then Put("Something strange is happening");
end if;
end;
The boolean attributeCallableis defined to yield the valueTrueif the des- ignated task is neitherCompleted,TerminatednorAbnormal. (An abnor- mal task is one that has been aborted; the conditions necessary for an abnormal task to become terminated are discussed in Chapter 9.) In the above example, if taskChild 2fails in its elaboration, then the declaring block will display an ap- propriate error message. TaskChild 1will, however, be unaffected by this and will proceed in its execution. The declarative block will only exit if, and when, Child 1subsequently terminates.
Another task attribute isTerminated, which returns Trueif the named task has terminated; returnsFalseotherwise.
Tasks states without task hierarchies
Figure 4.2 illustrates those task states and their transitions that have been intro- duced so far. The state transition diagram will be extended in this and later chap- ters. Note that ‘activating’ and ‘executing’ are definitions of the state of the task;
they do not imply that the task is actually running on the processor. This is an im-
Fig. 4.2: Task states
plementation issue. Thus, for example, the state ‘executing’ means able to execute (make progress) if processing resources are made available to it.