THE CONDITIONAL RENDEZVOUS

IMPATIENT PROGRAMMING

Many times in your life you wish to do something but you decide after trying for a short period of time, that it cannot be done, so you change your mind and do something else. This capability must be available in a computer program also, since a computer program is often used to simulate something in real life. This chapter will give examples of impatient programs, those that refuse to simply wait forever for a certain job to be done.

THE BASIC PROGRAM OUTLINE

Examine the file named e_c28_p1.ada for the program that will serve as the outline for the selective rendezvous even though it does not contain one. The program consists of four tasks, one each to describe Bill's day and John's day, and one each to describe eating a meal at a restaurant and at a fast food Burger Boy (hopefully not an actual restaurant). In this program, all of the delay times have been defined in terms of a constant named HOURS which actually causes a delay of one second per hour to speed up program execution to a reasonable level.

Eating a meal at the restaurant requires half an hour to be served and another half hour to consume the meal, whereas the Burger Boy requires only one tenth of an hour to be served and another tenth to consume the meal. The task named Bills_Day has him eating three meals only one hour apart, and the task named Johns_Day has him eating two meals in rapid succession then waiting four hours until he eats supper. Another interesting point is the fact that both eat every meal at the restaurant with no concern for how long they have to wait to be seated and eat. It is of no concern either to the Ada program at hand or the analysis of the problem, that one of the tasks is never called, because this is perfectly legal. Finally, both the restaurant and the Burger Boy can only serve one customer at a time, since this is the way the tasks were programmed. They can however, each serve a different customer at the same time.

EATING MEALS IS VERY SLOW

You will notice, by inspecting the delays, that John waits 0.4 hours and gets to the restaurant first, then takes a total of one hour to eat. Bill waits one hour, and goes to the restaurant, but must wait on the entry queue for 0.4 hours for John to finish eating, then takes another hour to eat. During this hour, John has returned and is waiting to be served again. They continue getting in each others way and finally each consumes three meals.

The observant student will notice that the tasks named Bills_Day and Johns_Day each run through sequentially to completion and make no additional calls. The two named Restaurant and Burger_Boy however, each consist of an infinite loop and never actually complete. When the first two tasks execute to completion, the system will recognize that there are no tasks running that are capable of making calls to the waiting accept statements. The system will recognize this condition, and it will terminate the program due to deadlock after displaying a message that deadlock has occurred.

We still have not given an acceptable method of terminating our program gracefully, but we will later in this chapter. You should spend the time necessary to thoroughly understand this program since it will be the basis for the remaining example programs in this chapter. When you do understand it, compile and execute it to see if your compiler will recognize the deadlock condition.

THE CONDITIONAL RENDEZVOUS

Examine the program named e_c28_p2.ada for our first example of a conditional rendezvous. This program is identical to the last one named e_c28_p1.ada except for the addition of a few statements in the task named Bills_Day. In this program Bill is in a bit of a hurry to eat his first two meals and puts in a few conditions to indicate this.

THE SELECTED RENDEZVOUS

When Bill starts his day, he is very impatient and will not wait at all for his first meal. If the restaurant is not ready to serve a meal immediately, he will go to the Burger Boy and have his breakfast. The statements in lines 29 through 33 replace the single statement of the last program to indicate this impatience. In Ada terms, if the task named Restaurant is not waiting at the Eat_A_Meal entry point, the call will not be made there, but a call will be made to the entry point named Eat_A_Meal in the Burger_Boy task. If the Burger_Boy task is not waiting at the entry point, then Bill will be required to wait until it is ready, when he will be served.

The reserved word else is used to indicate the selected rendezvous and it can follow as many or clauses as desired. The general form is;

```    select
<entry call>;
or
>entry call>;
else
<entry call>;
end select;```
The else clause will be taken if none of the other entry points are waiting at their respective rendezvous points.

THE DELAYED RENDEZVOUS

Bill is not quite as hungry for his second meal so he is willing to wait for a short period at the restaurant, but if he is not served within one tenth of an hour, he will go to the Burger Boy for lunch. The single statement in lines 35 through 40 replaces the single statement in the previous program. In Ada terms, the task named Bills_Day will wait .1 hour for the Restaurant task to reach its entry point, after which it will call the entry point of Burger_Boy and wait no matter how long it takes to be served there.

As many selections as desired can be used, with delay statements in as many of the selections as needed. The general form is given by;

```    select
delay <time>;
<entry call>;
or
delay <time>;
<entry call>;
or
delay <time>;
<entry call>;
end select;```
An else clause cannot be used if any delay statements are used because the else clause will be executed immediately and any statement with a delay would never have a chance to time out. It would therefore never be executed and must be regarded as unexecutable code.

BILL'S STUBBORN RESOLUTION FOR SUPPER

Bill has decided that under no conditions will he eat supper at the Burger Boy. He will wait for as long as necessary in order to be served at the restaurant, and this is reflected in the single call in line 42 in exactly the same manner that was indicated in the previous program.

Take careful notice that both of these select statements are in the calling task, not the called task, but we will see shortly that the same sort of things are available in the called task.

Examination of the result of execution will reveal that Bill did eat both of his early meals at the Burger Boy. In addition, you will see that his second meal was ordered and eaten at the Burger Boy during the time that John was eating his meal at the Restaurant. This indicates that resources are being well used.

Be sure to compile and execute this program. Observe the result of execution to see that it does send Bill to the Burger Boy on occasion. Because we still have no graceful termination, deadlock occurs once again.

THE DELAYED ENTRY POINT

Examine the program named e_c28_p3.ada for yet another addition to our example of Bill and John satisfying their desire for nourishment. In this case, the restaurant will not remain open forever, nor will the Burger Boy, both choosing to close for the day if there are no customers for a period of time.

The select statement in lines 59 through 72 contains two alternatives, one to handle a customer as usual, and another with a delay of 1.5 hours followed by a restaurant closing statement. If there are no entry calls to the entry named Eat_A_Meal for 1.5 seconds (since HOURS is actually one second), then the second branch of the select statement will be executed, resulting in the display of a message and execution of an exit statement. You will recall that an exit will take you out of the most immediate loop and continue execution of statements from that point. In the case of the Restaurant task, the task is therefore completed and waits for the other tasks to complete.

The task named Burger_Boy has the same alternative entry point, except for a delay of 2.1 seconds. It also reaches its end statement and waits for the others to finish. Examination of the result of execution will reveal that both eating establishments actually did reach timeout and closed for the day leaving John to go hungry since he never ate his third meal. Since John did not eat his third meal of the day, some code was not executed and it was not reported as such. This seems to be an error, but it is actually not, because it is a tasking error that is not propagated to the main program. This is according to the definition of Ada and is explained more fully in the last two paragraphs of this chapter.

Be sure to compile and run this program and observe the early closing of the eating establishments.

Examine the program named e_c28_p4.ada for an example of orderly termination of tasks. This program is identical to the first program in this chapter named e_c28_p1.ada except for two minor changes. The entry point for the task named Restaurant has been put inside of a select statement in a manner similar to that done in e_c28_p2.ada or e_c28_p3.ada but a different or clause is used, one that contains the reserved word terminate. Each time through the loop, the entry point named Eat_A_Meal can be selected for execution and the task execution will wait until this entry point is called. While the program is waiting for the entry call, the branch of the select with the terminate allows the possibility of a termination to occur. However, the termination can only occur under the right conditions. The right conditions require that all other concurrent tasks, including the task in the main program, are either at their final end waiting to terminate, or have a similar terminate alternative to select.

The task named Burger_Boy has a similar terminate alternative. When the two calling tasks reach their final end, the two serving tasks have terminate alternatives available, so there is an orderly termination and the program returns to the operating system. Be sure to compile and execute this program, then study the result for conformance to this definition.

THE abort STATEMENT

The abort statement will unconditionally abort any tasks with no regard to their present operating condition. It is extremely abrupt and does not provide for an orderly termination. It should therefore be used only in conditions of an emergency nature. Possibly the detection of loss of power would be such a circumstance. The tasks to be aborted are listed following the reserved word abort in an executable statement anywhere that it is legal to use an executable statement.

There are two useful task attributes that can be used to find the condition of any given task. They are CALLABLE, and TERMINATED, and each returns a BOOLEAN type indication of the current status of the task to which the attribute is appended. See the ARM for details on the use of these two attributes.

The tasking exception named Tasking_Error is raised during essentially any communication error. Any error during task elaboration will raise this exception (this will be illustrated in a later example program). This exception is raised in the caller if the called task is aborted, and is raised in the originators of all calls on an entry queue of an aborted task.

If an exception is raised during a rendezvous, it is propagated into both tasks since each may need some form of recovery. If the exception is not handled internally by the task, it is not propagated to the calling program because to do so would be very disruptive. This means that a program that appears to be working correctly could actually have a very disruptive tasking error, much like the example program named e_c28_p3.ada in this chapter. Each significant task should therefore have an exception handler to guard against the occurrence of an unknown exception.

PROGRAMMING EXERCISE

1. Modify the program named e_c28_p2.ada such that it has an orderly termination upon completion.(Solution)
2. Modify e_c28_p2.ada even further such that John eats every meal at the Burger Boy unless he has to wait there, in which case he eats at the restaurant.(Solution)