|Ada 95 Quality and Style Guide||Chapter 6|
6.2.2 Defensive Task Communication
Provide a handler for exception Program_Error whenever you cannot avoid a selective accept statement whose alternatives can all be closed (Honeywell 1986).
Make systematic use of handlers for Tasking_Error.
Be prepared to handle exceptions during a rendezvous .
Consider using a when others exception handler.
This block allows recovery from exceptions raised while attempting to communicate a command to another task:Accelerate: begin Throttle.Increase(Step); exception when Tasking_Error => ... when Constraint_Error => ... when Throttle_Too_Wide => ... ... end Accelerate;
In this select statement, if all the guards happen to be closed, the program can continue by executing the else part. There is no need for a handler for Program_Error. Other exceptions can still be raised while evaluating the guards or attempting to communicate. You will also need to include an exception handler in the task Throttle so that it can continue to execute after an exception is raised during the rendezvous:... Guarded: begin select when Condition_1 => accept Entry_1; or when Condition_2 => accept Entry_2; else -- all alternatives closed ... end select; exception when Constraint_Error => ... end Guarded;
In this select statement, if all the guards happen to be closed, exception Program_Error will be raised. Other exceptions can still be raised while evaluating the guards or attempting to communicate:Guarded: begin select when Condition_1 => accept Entry_1; or when Condition_2 => delay Fraction_Of_A_Second; end select; exception when Program_Error => ... when Constraint_Error => ... end Guarded; ...
The exception Program_Error is raised if a selective accept statement (select statement containing accepts) is reached, all of whose alternatives are closed (i.e., the guards evaluate to False and there are no alternatives without guards), unless there is an else part. When all alternatives are closed, the task can never again progress, so there is by definition an error in its programming. You must be prepared to handle this error should it occur.
Because an else part cannot have a guard, it can never be closed off as an alternative action; thus, its presence prevents Program_Error. However, an else part, a delay alternative, and a terminate alternative are all mutually exclusive, so you will not always be able to provide an else part. In these cases, you must be prepared to handle Program_Error.
The exception Tasking_Error can be raised in the calling task whenever it attempts to communicate. There are many situations permitting this. Few of them are preventable by the calling task.
If an exception is raised during a rendezvous and not handled in the accept statement, it is propagated to both tasks and must be handled in two places (see Guideline 5.8).
The handling of the others exception can be used to avoid propagating unexpected exceptions to callers (when this is the desired effect) and to localize the logic for dealing with unexpected exceptions in the rendezvous. After handling, an unknown exception should normally be raised again because the final decision of how to deal with it might need to be made at the outermost scope of the task body.
There are other ways to prevent Program_Error at a selective accept. These involve leaving at least one alternative unguarded or proving that at least one guard will evaluate True under all circumstances. The point here is that you or your successors will make mistakes in trying to do this, so you should prepare to handle the inevitable exception.
|< Previous Page||Search||Contents||Index||Next Page >|