|Ada 95 Quality and Style Guide||Chapter 6|
6.3.2 Normal Termination
Do not create nonterminating tasks unintentionally.
Explicitly shut down tasks that depend on library packages.
Confirm that a task is terminated before freeing it with Ada.Unchecked_Deallocation.
Consider using a select statement with a terminate alternative rather than an accept statement alone.
Consider providing a terminate alternative for every selective accept that does not require an else part or a delay .
Do not declare or create a task within a user-defined Finalize procedure after the environment task has finished waiting for other tasks.
This task will never terminate:--------------------------------------------------------------------- task body Message_Buffer is ... begin -- Message_Buffer loop select when Head /= Tail => -- Circular buffer not empty accept Retrieve (Value : out Element) do ... end Retrieve; or when not ((Head = Index'First and then Tail = Index'Last) or else (Head /= Index'First and then Tail = Index'Pred(Head)) ) => -- Circular buffer not full accept Store (Value : in Element); end select; end loop; ... end Message_Buffer; ---------------------------------------------------------------------
The implicit environment task does not terminate until all other tasks have terminated. The environment task serves as a master for all other tasks created as part of the execution of the partition; it awaits termination of all such tasks in order to perform finalization of any remaining objects of the partition. Thus, a partition will exist until all library tasks are terminated.
A nonterminating task is a task whose body consists of a nonterminating loop with no selective accept with terminate or a task that depends on a library package. Execution of a subprogram or block containing a task cannot complete until the task terminates. Any task that calls a subprogram containing a nonterminating task will be delayed indefinitely.
A task that depends on a library package cannot be forced to terminate using a selective accept construct with alternative and should be terminated explicitly during program shutdown. One way to explicitly shut down tasks that depend on library packages is to provide them with exit entries and have the main subprogram call the exit entry just before it terminates.
The Ada Reference Manual (1995, §13.11.2) states that a bounded error results from freeing a discriminated, unterminated task object. The danger lies in deallocating the discriminants as a result of freeing the task object. The effect of unterminated tasks containing bounded errors at the end of program execution is undefined.
Execution of an accept statement or of a selective accept statement without an else part, a delay, or a terminate alternative cannot proceed if no task ever calls the entry(s) associated with that statement. This could result in deadlock. Following the guideline to provide a terminate alternative for every selective accept without an else or a delay entails programming multiple termination points in the task body. A reader can easily "know where to look" for the normal termination points in a task body. The termination points are the end of the body's sequence of statements and alternatives to select statements.
When the environment task has been terminated, either normally or abnormally, the language does not specify whether to await a task activated during finalization of the controlled objects in a partition. While the environment task is waiting for all other tasks in the partition to complete, starting up a new task during finalization results in a bounded error (Ada Reference Manual 1995, §10.2). The exception Program_Error can be raised during creation or activation of such a task.
If you are implementing a cyclic executive, you might need a scheduling task that does not terminate. It has been said that no real-time system should be programmed to terminate. This is extreme. Systematic shutdown of many real-time systems is a desirable safety feature.
If you are considering programming a task not to terminate, be certain that it is not a dependent of a block or subprogram from which the task's caller(s) will ever expect to return. Because entire programs can be candidates for reuse (see Chapter 8), note that the task (and whatever it depends upon) will not terminate. Also be certain that for any other task that you do wish to terminate, its termination does not await this task's termination. Reread and fully understand the Ada Reference Manual (1995, §9.3) on "Task Dependence-Termination of Tasks."
|< Previous Page||Search||Contents||Index||Next Page >|