home *** CD-ROM | disk | FTP | other *** search
-
-
-
- Chapter 25
- THE SIMPLE RENDEZVOUS
-
-
- COMMUNICATION BETWEEN TASKS
- _________________________________________________________________
-
- In the last chapter, we ran a few programs with tasking, but they
- all used simple tasking with no form of synchronization. In a real
- situation using tasking, some form of communication between tasks
- will be required so we will study the simple rendezvous in this
- chapter.
-
- Examine the program named HOTDOG.ADA which will ================
- illustrate the simple rendezvous. This program HOTDOG.ADA
- consists of two tasks, the one in lines 10 ================
- through 25 and the main program itself.
-
-
- THE entry STATEMENT
- _________________________________________________________________
-
- The task specification is a little more complicated here than it
- was in any of the example programs in the last chapter because we
- have an entry point declared in the task. The reserved word entry
- begins the entry declaration and is followed by the entry name,
- which is Make_A_Hot_Dog in this case. The entry statement defines
- the interface to the outside of a task in much the same way as the
- procedure header defines the external interface to a package in the
- package specification. Unlike a package, no types, variables, or
- constants are allowed to be declared in the task specification, but
- there is no limit to the number of entry points allowed. An entry
- can have formal parameters declared as part of the entry name, (we
- will have an example in the next example program), but it cannot
- have a return parameter similar to a function. One or more of the
- formal parameters is permitted to have a parameter of mode out or
- in out however, so data can be passed both ways while a
- synchronization is effected. The in mode is also permitted. We
- will have more to say about this topic later in this chapter.
-
-
- THE accept STATEMENT
- _________________________________________________________________
-
- The task body is a very simple sequence of statements in which a
- message is output to the monitor, a loop is executed four times,
- and another message is output. The thing that is new here is the
- accept statement within the loop. The accept statement begins with
- the reserved word accept and has the following general form;
-
- accept <entry-name> do
- <executable statements>
- end <entry-name>;
-
- Page 25-1
-
- Chapter 25 - The Simple Rendezvous
-
-
- and any legal Ada statements can be contained within it. When
- execution of the task reaches the accept statement, the task "goes
- to sleep" until some other task makes a call to this particular
- accept statement. The term "goes to sleep" means that the task
- does not simply sit there and execute a do nothing loop while it
- is waiting, effectively wasting the resources of the system.
- Instead, it is actually doing nothing until it is awakened by an
- entry call. It is also possible to have an accept statement with
- no statements contained within it. It will have the following
- form;
-
- accept <entry-name>;
-
- This statement will only be used for task synchronization since
- there is no data passed to the entered task.
-
-
- THE ENTRY CALL
- _________________________________________________________________
-
- The main part of the program is another loop with four iterations
- followed by a statement to display a line of text on the monitor.
- The only thing unusual about the loop is the statement in line 29
- which is an entry call to the entry named Make_A_Hot_Dog in the
- task named Gourmet. Keep in mind that these are two tasks that are
- operating in parallel and we will carefully explain what is
- happening.
- The entry call is executed at line 29 which wakes up the sleeping
- task at line 18 and the task named Gourmet continues from where it
- went to sleep. Notice that the calling program is not controlling
- the execution of Gourmet, but Gourmet itself is in control now that
- it has been allowed to continue operation. The entry call is not
- like a procedure call where the sequence of operation continues in
- the procedure, but is instead only a synchronization call that
- allows Gourmet to continue what it was doing prior to being put to
- sleep.
-
-
- WHAT IS THE CALLING PROGRAM DOING NOW?
- _________________________________________________________________
-
- During the time that the called task is executing statements within
- its accept block, the calling task is effectively put to sleep, and
- must wait until the called task completes its accept block. When
- Gourmet reaches line 22, both tasks are allowed to operate in
- parallel again until one or both reach their point of rendezvous
- again. If the main program reaches its entry call before Gourmet
- is ready to accept the call, then the main program will wait until
- Gourmet is ready. The accept statement, and the corresponding
- entry call, are therefore used to synchronize the two tasks.
-
- If you were to move the end of Make_A_Hot_Dog to the line
- immediately after the accept statement, including a null of course,
-
- Page 25-2
-
- Chapter 25 - The Simple Rendezvous
-
- the output statements would then be running in parallel. The
- delays have been selected in such a way that after making this
- change, the hot dog would be eaten before it was made. This is one
- of the programming exercises at the end of this chapter.
-
-
- A COUPLE OF FINE POINTS MUST BE MADE HERE
- _________________________________________________________________
-
- Although the entry call looks very much like a procedure call, it
- is different because it is not legal to use a use clause for a
- task. It is required therefore that every entry call must use the
- extended naming convention, or the "dotted" notation. Renaming can
- be used to reduce the size of the names used and will be
- illustrated in the next program.
-
- You will notice that the two tasks were composed of exactly four
- calls and four executions of the accept statement. This was done
- on purpose in order to simplify the problem of task termination at
- this point in our study. The study of task termination will be
- covered in detail in the next chapter. Until then, you should see
- what happens when the two loops are different. Change the loop in
- Gourmet to 5 iterations and see what happens if it waits to accept
- a call that never comes, then make the loop in the main program
- bigger to see what happens when there is nothing to accept its
- call. We will study tasking exceptions in a later chapter of this
- tutorial. The execution of a return statement (not illustrated
- here), within an accept statement corresponds to reaching the final
- end and effectively terminates the rendezvous.
-
-
- SERVERS AND USERS
- _________________________________________________________________
-
- Tasks are categorized into two rather loosely defined groups,
- server tasks and user tasks. A server task is one that accepts
- calls from other tasks, and a user task is one that makes calls to
- one or more server tasks. In the present example program, Gourmet
- is a server task, and the main program is a user task. Some tasks
- both accept calls and make calls, and they are referred to as
- intermediate tasks. This terminology, or some other fairly self
- defining terminology may be used in the literature about Ada, so
- you should be aware that such classifications may exist.
-
- Be sure to compile and execute this program making the changes
- suggested earlier and observe the results.
-
-
- MULTIPLE ENTRY POINTS
- _________________________________________________________________
-
- Examine the program named HOTDOGS.ADA for a few added tasking
- topics beginning with multiple accept statements. You will notice
- that there are three accept statements in the task body
-
- Page 25-3
-
- Chapter 25 - The Simple Rendezvous
-
- corresponding to a single entry point declared ===============
- in the task specification. There is no limit to HOTDOGS.ADA
- the number of accept statements and they are ===============
- executed when the logic causes execution to
- arrive at each one in turn. Remember that the
- task is executed in the logical order as defined in the sequence
- of statements, except that each time the logic causes execution to
- arrive at an accept statement, the task will "go to sleep" until
- an entry call is made to the waiting accept statement. Moreover,
- the logic does not care where the entry call comes from, nor does
- it know where it came from, it only cares that the entry call is
- made. Thus it is possible for several different tasks to be
- calling this entry point and allowing the task to progress through
- its logic. Because there is only one other task in this program,
- we know exactly where the entry call is being generated.
-
- Careful study of the logic will reveal that the accept statement
- in line 21 must be called, followed by four calls to line 29, and
- another call to line 39. After six calls to this entry point, the
- task will reach the end of its execution and will be completed.
- You will notice that we make exactly six calls to this entry point
- by the task which is the main program, so everything will come out
- right.
-
-
- RENAMING A TASK ENTRY
- _________________________________________________________________
-
- The alternate name, which is declared in line 14, is used in the
- main program task to illustrate the use of the renaming facility.
- Note that the dotted notation is not required in this case. Once
- again, you can change either the number of calls or the number of
- accepts to see the exception error or a deadlock condition.
-
-
-
- ENTRY PARAMETERS
- _________________________________________________________________
-
- You should have noticed by now that each of the accept statements
- has a formal parameter associated with it in the same manner that
- a subprogram can have. In fact, it is permissible to have as many
- parameters as you desire to transfer data either from the calling
- task to the called task or back the other way. All three modes of
- parameter passing are legal for use and the in mode will be used
- if none is specified as is done here. There is one difference in
- a task however, you are not permitted to have a return parameter
- like a function has, but you can return a value by using an out or
- an in out parameter.
-
- Since you can pass parameters both ways, the task appears to be
- executed just like a procedure, but there is a very definite
- difference as mentioned earlier. A procedure is actually executed
- by the calling program, but the task is simply let free to run on
-
- Page 25-4
-
- Chapter 25 - The Simple Rendezvous
-
- its own in parallel with the calling program. The task is not a
- subservient program but is running its own logic as it is coded to
- do.
-
- Be sure to compile and execute this program after you understand
- what it is supposed to do.
-
-
- MULTIPLE CALLING TASKS
- _________________________________________________________________
-
- Examine the program named MANYDOGS.ADA for an ================
- example of two tasks calling a third task's MANYDOGS.ADA
- entry point. The task named Gourmet has a ================
- single entry point, but this time there are two
- formal parameters declared in the task
- specification and the same two declared in the accept statement.
- These must agree of course. The entry point named Make_A_Hot_Dog
- in line 19 contains some text to display and a delay of 0.8 second,
- because it takes a little time to make a hot dog. You will notice
- that sometimes mustard is added, and sometimes it is not, depending
- on who is eating the result. We will say more about this later.
-
- We have two additional tasks in lines 35 through 56 named Bill and
- John, each of which executes in parallel, and each of which
- requests a number of hot dogs and consumes them in zero time, since
- there is no delay prior to their next request. You will also
- notice that once again the numbers come out right because Bill
- requests three hot dogs and John asks for two while the task that
- supplies them makes exactly five. We will discuss better methods
- of task termination later. For the time being, simply accept the
- utopian situation depicted here.
-
-
- ENTRIES STACK UP AT THE ENTRY POINT
- _________________________________________________________________
-
- Considering all that we have said so far about tasking, you should
- understand that all three of these tasks begin execution at the
- same time and Bill and John both request a hot dog immediately.
- Since there is only one entry point, only one can be served at a
- time, and the Ada definition does not specify which will be
- serviced first. It does specify that both will ultimately be
- served, so there is an implicit queue at the entry point where
- requests can be stored until they can be serviced in turn. All
- requests are serviced on a First In First Out (FIFO) basis with no
- concern for priority of tasks (to be defined later). This queue
- is a "hidden" queue as far as you, the programmer, are concerned
- because you have no access to it. You cannot therefore, sort
- through the entries and redefine the order of execution of the
- various entry requests. The attribute named COUNT is available
- which will return the number of requests pending on any entry
- queue. Its use will be illustrated in the program named FAMILY.ADA
- in chapter 27 of this tutorial.
-
- Page 25-5
-
- Chapter 25 - The Simple Rendezvous
-
-
- After we study some of the advanced tasking topics, you will have
- the ability to define several queues with different priorities and
- set up your own priorities as needed.
-
-
-
- THE ORDER OF OUTPUT IS SORT OF ODD
- _________________________________________________________________
-
- Back to the program at hand. Examining the result of execution
- will reveal that for some unknown reason, the task named John made
- the first request and the task named Gourmet made a hot dog with
- mustard first, because John's task was the one requesting a hot dog
- with mustard. However, before John was allowed to continue
- execution, the Gourmet task continued and serviced the next call
- in its entry queue for Make_A_Hot_Dog, and made a hot dog without
- mustard for Bill. At this point Gourmet had completed all of its
- entry calls and allowed one of the other tasks to run. The task
- named John was then allowed to continue execution. John ate his
- hot dog and requested another. Once again, by some undefined
- method, the task named Gourmet was allowed to run and make a second
- hot dog for John, with mustard, when Bill still hasn't been allowed
- to eat his first one. This continues until all conditions have
- been satisfied, which means that five hot dogs have been made, and
- all five have been consumed. Both consuming tasks declare their
- lack of hunger, and the task named Gourmet declares that it is out
- of hot dogs. The program has finally run to completion.
-
-
-
- WHAT ABOUT THE FUNNY ORDER OF RESULTS?
- _________________________________________________________________
-
- Even though the results seemed to come out in a funny order, they
- did follow all the rules we set down for them to follow. Remember
- that as an experienced programmer, you are accustomed to seeing
- everything come out in a very well defined precise order, because
- you have spent your programming career writing sequential programs.
- If you look at this output from the point of view of each task,
- you will see that the output from each task is perfectly
- sequential, as defined by the logic of the task. Additionally, you
- will see that the order of execution has been preserved as defined
- by the various rendezvous, because nobody eats a hot dog before it
- is made, and there are no hot dogs made too early. The
- synchronization of the tasks has been done exactly as we requested.
-
- Spend enough time studying the logic here to completely understand
- what is happening, then compile and execute this program to see if
- your compiler does anything in a different order.
-
-
-
-
-
- Page 25-6
-
- Chapter 25 - The Simple Rendezvous
-
- THE select STATEMENT
- _________________________________________________________________
-
- Examine the program named RETAIL1.ADA for our ===============
- first example program using a select statement. RETAIL1.ADA
- The select statement is used to allow a task to ===============
- select between two or more alternative entry
- points. In effect, a task can be waiting at two
- or more entry points for an entry call to be made, and can act on
- the first occurring entry call. The structure of the select
- statement is given by;
-
- select
- accept ...; -- Complete entry point logic
- or
- accept ...; -- Complete entry point logic
- or
- accept ...; -- Complete entry point logic
- end select;
-
- and is illustrated in lines 23 through 33 of the present example
- program. In this case there are two select alternatives, but there
- is no limit to the number of selections. Each additional branch
- is delimited by the reserved word or. When program control of the
- task arrives at the select statement in line 23, either entry call
- can be accepted and acted upon immediately.
-
-
-
- THE OVERALL PROGRAM
- _________________________________________________________________
-
- Common sense tells us that we cannot deliver a hot dog until we
- stock the shelf with a hot dog, so the program has been written to
- reflect this. The task requires an entry call to
- Stock_With_A_Hot_Dog before it begins the loop with the select in
- it to assure that at least one hot dog will be available. After
- that, it doesn't care what the order of entry calls is because the
- select statement in the loop will allow them to occur in any order.
- This is a very simplistic approach to setting up a precedence
- requirement in an Ada task, but it is too simple to really be
- effective which we shall see when we examine some of the problems
- that can occur.
-
- In the first place, if the main program, or task, fails to call
- Stock_With_A_Hot_Dog first, the system will simply lock up with the
- calling program demanding a delivered hot dog and steadfastly
- refusing to continue until it does, and the called task refusing
- to deliver one until it has been stocked with one in line 16. The
- system is in deadlock with both tasks refusing to do anything. You
- can simulate this condition by reversing the two calls in lines 39
- and 40. Your compiler will probably give a message indicating
- deadlock has occurred and terminate operation of the program.
- Another problem has to do with the inflexibility of this program,
-
- Page 25-7
-
- Chapter 25 - The Simple Rendezvous
-
- since we have once again counted the number of calls required to
- complete the two tasks and programmed compatible numbers in the two
- tasks.
-
- A further problem involves the fact that, after one hot dog has
- been stocked, there is nothing to prevent us from taking delivery
- of hundreds of hot dogs without adding any more to the shelves.
-
- When you think you understand this program, compile and execute it,
- then we will go on to the next program where we will solve two of
- the three problems mentioned in connection with the present
- program.
-
-
- SELECT STATEMENTS WITH GUARDS
- _________________________________________________________________
-
- Examine the program named RETAIL2.ADA for an ===============
- example of a select statement with guards. The RETAIL2.ADA
- guards are used to guard the entry points of the ===============
- select statement to prevent the kinds of silly
- things that happened in the last program. The
- task body Retail_Hot_Dogs has been modified in this program to
- include guards in lines 29 and 37 for the select statement in lines
- 28 through 42. A guard is simply a BOOLEAN condition that must be
- satisfied before that particular entry point can be accepted and
- its logic executed. The general form of the select statement with
- guards is given as;
-
- select
- when <BOOLEAN condition> =>
- accept ...; -- Complete entry point logic
- or
- when <BOOLEAN condition> =>
- accept ...; -- Complete entry point logic
- or
- when <BOOLEAN condition> =>
- accept ...; -- Complete entry point logic
- end select;
-
- and there is no limit to the number of permissible selections, each
- being separated by the reserved word or. In fact, one or more of
- the selections can have no guard, in which case it is similar to
- having a guard which always evaluates to TRUE. When the select
- statement is encountered, each of the guards is evaluated for TRUE
- or FALSE, and those conditions that evaluate to TRUE are allowed
- to enter into the active wait state for an entry, while those that
- have guards evaluating to FALSE are not. Those with guards
- evaluating to FALSE are treated as if they didn't exist for this
- pass through the loop. Once the guards are evaluated upon entering
- the select statement, they are not reevaluated until the next time
- the select statement is encountered, but remain static. If all
- guards evaluate to FALSE for a given select statement, the
- exception Program_Error is raised.
-
- Page 25-8
-
- Chapter 25 - The Simple Rendezvous
-
-
- LIMITING THE NUMBER OF HOT DOGS ON THE SHELF
- _________________________________________________________________
-
- In this program, when the select statement is entered in line 28,
- the guard at line 29 is evaluated and if the number of hot dogs on
- the shelf is less than 8, then the accept statement in line 30 is
- enabled and we are permitted to stock the shelf with one more hot
- dog. If the number of hot dogs is greater than zero, as the guard
- at line 37 tests for us, then the accept statement in line 38 is
- enabled and we are allowed to deliver a hot dog. Even though we
- may be allowed to either stock the shelf with a hot dog, or deliver
- a hot dog, we must wait until some other task requests us to do so
- before we actually do one of the operations. It should be clear
- to you that in this particular case we will always be permitted to
- do at least one of the operations, and in many cases both will be
- permitted. If none of the guards evaluate to TRUE, then none of
- the selections can be taken, and the program is therefore
- effectively deadlocked and the exception named Tasking_Error will
- be raised. You, the programmer, can trap this exception in much
- the same way that you can trap any other exception and handle it
- in your own manner, but the rules are a little different for
- tasking exceptions than for exceptions raised during sequential
- operation. We will cover tasking exceptions in detail later.
-
- It should be pointed out that, even if a guard evaluates to FALSE,
- entries can be added to the entry queue and serviced during
- subsequent executions of the select statement when the guard may
- become TRUE. Because of this method of defining the entry queue,
- no calls to the entry are lost, and the operation is predictable.
-
- This program contains four tasks, counting the main program, with
- one named Five_Dogs stocking the shelf very quickly with five hot
- dogs, because of the short delay, and another removing five hot
- dogs a little slower. The main program stocks and retrieves four
- hot dogs rather slowly due to the relatively long time delay built
- into the loop.
-
-
- WATCH THE GUARDS DO THEIR JOB
- _________________________________________________________________
-
- When you run this program you will see very little action with the
- guards because of the selection of the guard limits. The five hot
- dogs are put on the shelf very quickly, but the upper limit of 8
- is never reached, and there are always hot dogs on the shelf to
- supply the limited demands. In fact, as listed in the result of
- execution, there are never more than 5 on the shelf, and always
- more than zero. You should compile and execute the program to see
- if your compiler does the same thing as the one used for this
- execution.
-
- Change line 29 so that the limit is 3, and recompile and execute
- the resulting program. In this case, you will very clearly see
-
- Page 25-9
-
- Chapter 25 - The Simple Rendezvous
-
- that the first guard prevents more than three hot dogs from being
- placed on the shelf. In effect it builds up the entry queue for
- the Stock_With_A_Hot_Dog entry point and requires the suppliers to
- wait for shelf space.
-
- Reverse the delays in lines 49 and 57, as your next exercise, so
- that the hot dogs are consumed much faster than they are stocked
- so that the guard on the entry point named Deliver_A_Hot_Dog will
- be needed to protect the delivery of too many hot dogs. In this
- case, the queue to this entry point will build up a list of
- requests to be satisfied as hot dogs are delivered.
-
-
- THIS PROGRAM IS MUCH BETTER
- _________________________________________________________________
-
- This program solved two of the three problems listed concerning the
- last program but we still must use the method of counting the
- required entry calls and providing the proper number of entries.
- As promised before, this problem will be remedied soon. Be sure
- you compile and execute this program three times, once unmodified,
- and twice with the suggested changes, then study the output to
- assure yourself that you understand it completely.
-
-
-
- PROGRAMMING EXERCISES
- _________________________________________________________________
-
- 1. Move the end of the accept statement in HOTDOG.ADA to the line
- immediately after the accept statement itself to see that it
- is possible to eat the hot dog before it is made because the
- tasks are both running at the same time.
-
- 2. Add another task to RETAIL2.ADA that executes a loop 10 times
- with a 0.3 second delay that outputs the current number of hot
- dogs on the shelf.
-
- 3. Using the package Calendar, output the elapsed time each time
- the new procedure defined in exercise 2 outputs the number of
- hot dogs on the shelf.
-
-
-
-
-
-
-
-
-
-
-
- Page 25-10