home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / programm / prog3 / chap25.txt < prev    next >
Encoding:
Text File  |  1991-07-01  |  26.5 KB  |  586 lines

  1.  
  2.  
  3.  
  4.                                                        Chapter 25
  5.                                             THE SIMPLE RENDEZVOUS
  6.  
  7.  
  8. COMMUNICATION BETWEEN TASKS
  9. _________________________________________________________________
  10.  
  11. In the last chapter, we ran a few programs with tasking, but they
  12. all used simple tasking with no form of synchronization.  In a real
  13. situation using tasking, some form of communication between tasks
  14. will be required so we will study the simple rendezvous in this
  15. chapter.
  16.  
  17. Examine the program named HOTDOG.ADA which will  ================
  18. illustrate the simple rendezvous.  This program     HOTDOG.ADA
  19. consists of two tasks, the one in lines 10       ================
  20. through 25 and the main program itself.
  21.  
  22.  
  23. THE entry STATEMENT
  24. _________________________________________________________________
  25.  
  26. The task specification is a little more complicated here than it
  27. was in any of the example programs in the last chapter because we
  28. have an entry point declared in the task.  The reserved word entry
  29. begins the entry declaration and is followed by the entry name,
  30. which is Make_A_Hot_Dog in this case.  The entry statement defines
  31. the interface to the outside of a task in much the same way as the
  32. procedure header defines the external interface to a package in the
  33. package specification.  Unlike a package, no types, variables, or
  34. constants are allowed to be declared in the task specification, but
  35. there is no limit to the number of entry points allowed.  An entry
  36. can have formal parameters declared as part of the entry name, (we
  37. will have an example in the next example program), but it cannot
  38. have a return parameter similar to a function.  One or more of the
  39. formal parameters is permitted to have a parameter of mode out or
  40. in out however, so data can be passed both ways while a
  41. synchronization is effected.  The in mode is also permitted.  We
  42. will have more to say about this topic later in this chapter.
  43.  
  44.  
  45. THE accept STATEMENT
  46. _________________________________________________________________
  47.  
  48. The task body is a very simple sequence of statements in which a
  49. message is output to the monitor, a loop is executed four times,
  50. and another message is output.  The thing that is new here is the
  51. accept statement within the loop.  The accept statement begins with
  52. the reserved word accept and has the following general form;
  53.  
  54.      accept <entry-name> do
  55.             <executable statements>
  56.      end <entry-name>;
  57.  
  58.                                                         Page 25-1
  59.  
  60.                                Chapter 25 - The Simple Rendezvous
  61.  
  62.  
  63. and any legal Ada statements can be contained within it.  When
  64. execution of the task reaches the accept statement, the task "goes
  65. to sleep" until some other task makes a call to this particular
  66. accept statement.  The term "goes to sleep" means that the task
  67. does not simply sit there and execute a do nothing loop while it
  68. is waiting, effectively wasting the resources of the system.
  69. Instead, it is actually doing nothing until it is awakened by an
  70. entry call.  It is also possible to have an accept statement with
  71. no statements contained within it.  It will have the following
  72. form;
  73.  
  74.      accept <entry-name>;
  75.  
  76. This statement will only be used for task synchronization since
  77. there is no data passed to the entered task.
  78.  
  79.  
  80. THE ENTRY CALL
  81. _________________________________________________________________
  82.  
  83. The main part of the program is another loop with four iterations
  84. followed by a statement to display a line of text on the monitor.
  85. The only thing unusual about the loop is the statement in line 29
  86. which is an entry call to the entry named Make_A_Hot_Dog in the
  87. task named Gourmet.  Keep in mind that these are two tasks that are
  88. operating in parallel and we will carefully explain what is
  89. happening.
  90. The entry call is executed at line 29 which wakes up the sleeping
  91. task at line 18 and the task named Gourmet continues from where it
  92. went to sleep.  Notice that the calling program is not controlling
  93. the execution of Gourmet, but Gourmet itself is in control now that
  94. it has been allowed to continue operation.  The entry call is not
  95. like a procedure call where the sequence of operation continues in
  96. the procedure, but is instead only a synchronization call that
  97. allows Gourmet to continue what it was doing prior to being put to
  98. sleep.
  99.  
  100.  
  101. WHAT IS THE CALLING PROGRAM DOING NOW?
  102. _________________________________________________________________
  103.  
  104. During the time that the called task is executing statements within
  105. its accept block, the calling task is effectively put to sleep, and
  106. must wait until the called task completes its accept block.  When
  107. Gourmet reaches line 22, both tasks are allowed to operate in
  108. parallel again until one or both reach their point of rendezvous
  109. again.  If the main program reaches its entry call before Gourmet
  110. is ready to accept the call, then the main program will wait until
  111. Gourmet is ready.  The accept statement, and the corresponding
  112. entry call, are therefore used to synchronize the two tasks.
  113.  
  114. If you were to move the end of Make_A_Hot_Dog to the line
  115. immediately after the accept statement, including a null of course,
  116.  
  117.                                                         Page 25-2
  118.  
  119.                                Chapter 25 - The Simple Rendezvous
  120.  
  121. the output statements would then be running in parallel.  The
  122. delays have been selected in such a way that after making this
  123. change, the hot dog would be eaten before it was made.  This is one
  124. of the programming exercises at the end of this chapter.
  125.  
  126.  
  127. A COUPLE OF FINE POINTS MUST BE MADE HERE
  128. _________________________________________________________________
  129.  
  130. Although the entry call looks very much like a procedure call, it
  131. is different because it is not legal to use a use clause for a
  132. task.  It is required therefore that every entry call must use the
  133. extended naming convention, or the "dotted" notation.  Renaming can
  134. be used to reduce the size of the names used and will be
  135. illustrated in the next program.
  136.  
  137. You will notice that the two tasks were composed of exactly four
  138. calls and four executions of the accept statement.  This was done
  139. on purpose in order to simplify the problem of task termination at
  140. this point in our study.  The study of task termination will be
  141. covered in detail in the next chapter.  Until then, you should see
  142. what happens when the two loops are different.  Change the loop in
  143. Gourmet to 5 iterations and see what happens if it waits to accept
  144. a call that never comes, then make the loop in the main program
  145. bigger to see what happens when there is nothing to accept its
  146. call.  We will study tasking exceptions in a later chapter of this
  147. tutorial.  The execution of a return statement (not illustrated
  148. here), within an accept statement corresponds to reaching the final
  149. end and effectively terminates the rendezvous.
  150.  
  151.  
  152. SERVERS AND USERS
  153. _________________________________________________________________
  154.  
  155. Tasks are categorized into two rather loosely defined groups,
  156. server tasks and user tasks.  A server task is one that accepts
  157. calls from other tasks, and a user task is one that makes calls to
  158. one or more server tasks.  In the present example program, Gourmet
  159. is a server task, and the main program is a user task.  Some tasks
  160. both accept calls and make calls, and they are referred to as
  161. intermediate tasks.  This terminology, or some other fairly self
  162. defining terminology may be used in the literature about Ada, so
  163. you should be aware that such classifications may exist.
  164.  
  165. Be sure to compile and execute this program making the changes
  166. suggested earlier and observe the results.
  167.  
  168.  
  169. MULTIPLE ENTRY POINTS
  170. _________________________________________________________________
  171.  
  172. Examine the program named HOTDOGS.ADA for a few added tasking
  173. topics beginning with multiple accept statements.  You will notice
  174. that there are three accept statements in the task body
  175.  
  176.                                                         Page 25-3
  177.  
  178.                                Chapter 25 - The Simple Rendezvous
  179.  
  180. corresponding to a single entry point declared    ===============
  181. in the task specification.  There is no limit to    HOTDOGS.ADA
  182. the number of accept statements and they are      ===============
  183. executed when the logic causes execution to
  184. arrive at each one in turn.  Remember that the
  185. task is executed in the logical order as defined in the sequence
  186. of statements, except that each time the logic causes execution to
  187. arrive at an accept statement, the task will "go to sleep" until
  188. an entry call is made to the waiting accept statement.  Moreover,
  189. the logic does not care where the entry call comes from, nor does
  190. it know where it came from, it only cares that the entry call is
  191. made.  Thus it is possible for several different tasks to be
  192. calling this entry point and allowing the task to progress through
  193. its logic.  Because there is only one other task in this program,
  194. we know exactly where the entry call is being generated.
  195.  
  196. Careful study of the logic will reveal that the accept statement
  197. in line 21 must be called, followed by four calls to line 29, and
  198. another call to line 39.  After six calls to this entry point, the
  199. task will reach the end of its execution and will be completed.
  200. You will notice that we make exactly six calls to this entry point
  201. by the task which is the main program, so everything will come out
  202. right.
  203.  
  204.  
  205. RENAMING A TASK ENTRY
  206. _________________________________________________________________
  207.  
  208. The alternate name, which is declared in line 14, is used in the
  209. main program task to illustrate the use of the renaming facility.
  210. Note that the dotted notation is not required in this case.  Once
  211. again, you can change either the number of calls or the number of
  212. accepts to see the exception error or a deadlock condition.
  213.  
  214.  
  215.  
  216. ENTRY PARAMETERS
  217. _________________________________________________________________
  218.  
  219. You should have noticed by now that each of the accept statements
  220. has a formal parameter associated with it in the same manner that
  221. a subprogram can have.  In fact, it is permissible to have as many
  222. parameters as you desire to transfer data either from the calling
  223. task to the called task or back the other way.  All three modes of
  224. parameter passing are legal for use and the in mode will be used
  225. if none is specified as is done here.  There is one difference in
  226. a task however, you are not permitted to have a return parameter
  227. like a function has, but you can return a value by using an out or
  228. an in out parameter.
  229.  
  230. Since you can pass parameters both ways, the task appears to be
  231. executed just like a procedure, but there is a very definite
  232. difference as mentioned earlier.  A procedure is actually executed
  233. by the calling program, but the task is simply let free to run on
  234.  
  235.                                                         Page 25-4
  236.  
  237.                                Chapter 25 - The Simple Rendezvous
  238.  
  239. its own in parallel with the calling program.  The task is not a
  240. subservient program but is running its own logic as it is coded to
  241. do.
  242.  
  243. Be sure to compile and execute this program after you understand
  244. what it is supposed to do.
  245.  
  246.  
  247. MULTIPLE CALLING TASKS
  248. _________________________________________________________________
  249.  
  250. Examine the program named MANYDOGS.ADA for an    ================
  251. example of two tasks calling a third task's        MANYDOGS.ADA
  252. entry point.  The task named Gourmet has a       ================
  253. single entry point, but this time there are two
  254. formal parameters declared in the task
  255. specification and the same two declared in the accept statement.
  256. These must agree of course.  The entry point named Make_A_Hot_Dog
  257. in line 19 contains some text to display and a delay of 0.8 second,
  258. because it takes a little time to make a hot dog.  You will notice
  259. that sometimes mustard is added, and sometimes it is not, depending
  260. on who is eating the result.  We will say more about this later.
  261.  
  262. We have two additional tasks in lines 35 through 56 named Bill and
  263. John, each of which executes in parallel, and each of which
  264. requests a number of hot dogs and consumes them in zero time, since
  265. there is no delay prior to their next request.  You will also
  266. notice that once again the numbers come out right because Bill
  267. requests three hot dogs and John asks for two while the task that
  268. supplies them makes exactly five.  We will discuss better methods
  269. of task termination later.  For the time being, simply accept the
  270. utopian situation depicted here.
  271.  
  272.  
  273. ENTRIES STACK UP AT THE ENTRY POINT
  274. _________________________________________________________________
  275.  
  276. Considering all that we have said so far about tasking, you should
  277. understand that all three of these tasks begin execution at the
  278. same time and Bill and John both request a hot dog immediately.
  279. Since there is only one entry point, only one can be served at a
  280. time, and the Ada definition does not specify which will be
  281. serviced first.  It does specify that both will ultimately be
  282. served, so there is an implicit queue at the entry point where
  283. requests can be stored until they can be serviced in turn.  All
  284. requests are serviced on a First In First Out (FIFO) basis with no
  285. concern for priority of tasks (to be defined later).  This queue
  286. is a "hidden" queue as far as you, the programmer, are concerned
  287. because you have no access to it.  You cannot therefore, sort
  288. through the entries and redefine the order of execution of the
  289. various entry requests.  The attribute named COUNT is available
  290. which will return the number of requests pending on any entry
  291. queue.  Its use will be illustrated in the program named FAMILY.ADA
  292. in chapter 27 of this tutorial.
  293.  
  294.                                                         Page 25-5
  295.  
  296.                                Chapter 25 - The Simple Rendezvous
  297.  
  298.  
  299. After we study some of the advanced tasking topics, you will have
  300. the ability to define several queues with different priorities and
  301. set up your own priorities as needed.
  302.  
  303.  
  304.  
  305. THE ORDER OF OUTPUT IS SORT OF ODD
  306. _________________________________________________________________
  307.  
  308. Back to the program at hand.  Examining the result of execution
  309. will reveal that for some unknown reason, the task named John made
  310. the first request and the task named Gourmet made a hot dog with
  311. mustard first, because John's task was the one requesting a hot dog
  312. with mustard.  However, before John was allowed to continue
  313. execution, the Gourmet task continued and serviced the next call
  314. in its entry queue for Make_A_Hot_Dog, and made a hot dog without
  315. mustard for Bill.  At this point Gourmet had completed all of its
  316. entry calls and allowed one of the other tasks to run.  The task
  317. named John was then allowed to continue execution.  John ate his
  318. hot dog and requested another.  Once again, by some undefined
  319. method, the task named Gourmet was allowed to run and make a second
  320. hot dog for John, with mustard, when Bill still hasn't been allowed
  321. to eat his first one.  This continues until all conditions have
  322. been satisfied, which means that five hot dogs have been made, and
  323. all five have been consumed.  Both consuming tasks declare their
  324. lack of hunger, and the task named Gourmet declares that it is out
  325. of hot dogs.  The program has finally run to completion.
  326.  
  327.  
  328.  
  329. WHAT ABOUT THE FUNNY ORDER OF RESULTS?
  330. _________________________________________________________________
  331.  
  332. Even though the results seemed to come out in a funny order, they
  333. did follow all the rules we set down for them to follow.  Remember
  334. that as an experienced programmer, you are accustomed to seeing
  335. everything come out in a very well defined precise order, because
  336. you have spent your programming career writing sequential programs.
  337. If you look at this output from the point of view of each task,
  338. you will see that the output from each task is perfectly
  339. sequential, as defined by the logic of the task.  Additionally, you
  340. will see that the order of execution has been preserved as defined
  341. by the various rendezvous, because nobody eats a hot dog before it
  342. is made, and there are no hot dogs made too early.  The
  343. synchronization of the tasks has been done exactly as we requested.
  344.  
  345. Spend enough time studying the logic here to completely understand
  346. what is happening, then compile and execute this program to see if
  347. your compiler does anything in a different order.
  348.  
  349.  
  350.  
  351.  
  352.  
  353.                                                         Page 25-6
  354.  
  355.                                Chapter 25 - The Simple Rendezvous
  356.  
  357. THE select STATEMENT
  358. _________________________________________________________________
  359.  
  360. Examine the program named RETAIL1.ADA for our     ===============
  361. first example program using a select statement.     RETAIL1.ADA
  362. The select statement is used to allow a task to   ===============
  363. select between two or more alternative entry
  364. points.  In effect, a task can be waiting at two
  365. or more entry points for an entry call to be made, and can act on
  366. the first occurring entry call.  The structure of the select
  367. statement is given by;
  368.  
  369.      select
  370.         accept ...;          -- Complete entry point logic
  371.      or
  372.         accept ...;          -- Complete entry point logic
  373.      or
  374.         accept ...;          -- Complete entry point logic
  375.      end select;
  376.  
  377. and is illustrated in lines 23 through 33 of the present example
  378. program.  In this case there are two select alternatives, but there
  379. is no limit to the number of selections.  Each additional branch
  380. is delimited by the reserved word or.  When program control of the
  381. task arrives at the select statement in line 23, either entry call
  382. can be accepted and acted upon immediately.
  383.  
  384.  
  385.  
  386. THE OVERALL PROGRAM
  387. _________________________________________________________________
  388.  
  389. Common sense tells us that we cannot deliver a hot dog until we
  390. stock the shelf with a hot dog, so the program has been written to
  391. reflect this.  The task requires an entry call to
  392. Stock_With_A_Hot_Dog before it begins the loop with the select in
  393. it to assure that at least one hot dog will be available.  After
  394. that, it doesn't care what the order of entry calls is because the
  395. select statement in the loop will allow them to occur in any order.
  396. This is a very simplistic approach to setting up a precedence
  397. requirement in an Ada task, but it is too simple to really be
  398. effective which we shall see when we examine some of the problems
  399. that can occur.
  400.  
  401. In the first place, if the main program, or task, fails to call
  402. Stock_With_A_Hot_Dog first, the system will simply lock up with the
  403. calling program demanding a delivered hot dog and steadfastly
  404. refusing to continue until it does, and the called task refusing
  405. to deliver one until it has been stocked with one in line 16.  The
  406. system is in deadlock with both tasks refusing to do anything.  You
  407. can simulate this condition by reversing the two calls in lines 39
  408. and 40.  Your compiler will probably give a message indicating
  409. deadlock has occurred and terminate operation of the program.
  410. Another problem has to do with the inflexibility of this program,
  411.  
  412.                                                         Page 25-7
  413.  
  414.                                Chapter 25 - The Simple Rendezvous
  415.  
  416. since we have once again counted the number of calls required to
  417. complete the two tasks and programmed compatible numbers in the two
  418. tasks.
  419.  
  420. A further problem involves the fact that, after one hot dog has
  421. been stocked, there is nothing to prevent us from taking delivery
  422. of hundreds of hot dogs without adding any more to the shelves.
  423.  
  424. When you think you understand this program, compile and execute it,
  425. then we will go on to the next program where we will solve two of
  426. the three problems mentioned in connection with the present
  427. program.
  428.  
  429.  
  430. SELECT STATEMENTS WITH GUARDS
  431. _________________________________________________________________
  432.  
  433. Examine the program named RETAIL2.ADA for an      ===============
  434. example of a select statement with guards.  The     RETAIL2.ADA
  435. guards are used to guard the entry points of the  ===============
  436. select statement to prevent the kinds of silly
  437. things that happened in the last program.  The
  438. task body Retail_Hot_Dogs has been modified in this program to
  439. include guards in lines 29 and 37 for the select statement in lines
  440. 28 through 42.  A guard is simply a BOOLEAN condition that must be
  441. satisfied before that particular entry point can be accepted and
  442. its logic executed.  The general form of the select statement with
  443. guards is given as;
  444.  
  445.      select
  446.         when <BOOLEAN condition> =>
  447.            accept ...;               -- Complete entry point logic
  448.      or
  449.         when <BOOLEAN condition> =>
  450.            accept ...;               -- Complete entry point logic
  451.      or
  452.         when <BOOLEAN condition> =>
  453.            accept ...;               -- Complete entry point logic
  454.      end select;
  455.  
  456. and there is no limit to the number of permissible selections, each
  457. being separated by the reserved word or.  In fact, one or more of
  458. the selections can have no guard, in which case it is similar to
  459. having a guard which always evaluates to TRUE.  When the select
  460. statement is encountered, each of the guards is evaluated for TRUE
  461. or FALSE, and those conditions that evaluate to TRUE are allowed
  462. to enter into the active wait state for an entry, while those that
  463. have guards evaluating to FALSE are not.  Those with guards
  464. evaluating to FALSE are treated as if they didn't exist for this
  465. pass through the loop.  Once the guards are evaluated upon entering
  466. the select statement, they are not reevaluated until the next time
  467. the select statement is encountered, but remain static.  If all
  468. guards evaluate to FALSE for a given select statement, the
  469. exception Program_Error is raised.
  470.  
  471.                                                         Page 25-8
  472.  
  473.                                Chapter 25 - The Simple Rendezvous
  474.  
  475.  
  476. LIMITING THE NUMBER OF HOT DOGS ON THE SHELF
  477. _________________________________________________________________
  478.  
  479. In this program, when the select statement is entered in line 28,
  480. the guard at line 29 is evaluated and if the number of hot dogs on
  481. the shelf is less than 8, then the accept statement in line 30 is
  482. enabled and we are permitted to stock the shelf with one more hot
  483. dog.  If the number of hot dogs is greater than zero, as the guard
  484. at line 37 tests for us, then the accept statement in line 38 is
  485. enabled and we are allowed to deliver a hot dog.  Even though we
  486. may be allowed to either stock the shelf with a hot dog, or deliver
  487. a hot dog, we must wait until some other task requests us to do so
  488. before we actually do one of the operations.  It should be clear
  489. to you that in this particular case we will always be permitted to
  490. do at least one of the operations, and in many cases both will be
  491. permitted.  If none of the guards evaluate to TRUE, then none of
  492. the selections can be taken, and the program is therefore
  493. effectively deadlocked and the exception named Tasking_Error will
  494. be raised.  You, the programmer, can trap this exception in much
  495. the same way that you can trap any other exception and handle it
  496. in your own manner, but the rules are a little different for
  497. tasking exceptions than for exceptions raised during sequential
  498. operation.  We will cover tasking exceptions in detail later.
  499.  
  500. It should be pointed out that, even if a guard evaluates to FALSE,
  501. entries can be added to the entry queue and serviced during
  502. subsequent executions of the select statement when the guard may
  503. become TRUE.  Because of this method of defining the entry queue,
  504. no calls to the entry are lost, and the operation is predictable.
  505.  
  506. This program contains four tasks, counting the main program, with
  507. one named Five_Dogs stocking the shelf very quickly with five hot
  508. dogs, because of the short delay, and another removing five hot
  509. dogs a little slower.  The main program stocks and retrieves four
  510. hot dogs rather slowly due to the relatively long time delay built
  511. into the loop.
  512.  
  513.  
  514. WATCH THE GUARDS DO THEIR JOB
  515. _________________________________________________________________
  516.  
  517. When you run this program you will see very little action with the
  518. guards because of the selection of the guard limits.  The five hot
  519. dogs are put on the shelf very quickly, but the upper limit of 8
  520. is never reached, and there are always hot dogs on the shelf to
  521. supply the limited demands.  In fact, as listed in the result of
  522. execution, there are never more than 5 on the shelf, and always
  523. more than zero.  You should compile and execute the program to see
  524. if your compiler does the same thing as the one used for this
  525. execution.
  526.  
  527. Change line 29 so that the limit is 3, and recompile and execute
  528. the resulting program.  In this case, you will very clearly see
  529.  
  530.                                                         Page 25-9
  531.  
  532.                                Chapter 25 - The Simple Rendezvous
  533.  
  534. that the first guard prevents more than three hot dogs from being
  535. placed on the shelf.  In effect it builds up the entry queue for
  536. the Stock_With_A_Hot_Dog entry point and requires the suppliers to
  537. wait for shelf space.
  538.  
  539. Reverse the delays in lines 49 and 57, as your next exercise, so
  540. that the hot dogs are consumed much faster than they are stocked
  541. so that the guard on the entry point named Deliver_A_Hot_Dog will
  542. be needed to protect the delivery of too many hot dogs.  In this
  543. case, the queue to this entry point will build up a list of
  544. requests to be satisfied as hot dogs are delivered.
  545.  
  546.  
  547. THIS PROGRAM IS MUCH BETTER
  548. _________________________________________________________________
  549.  
  550. This program solved two of the three problems listed concerning the
  551. last program but we still must use the method of counting the
  552. required entry calls and providing the proper number of entries.
  553. As promised before, this problem will be remedied soon.  Be sure
  554. you compile and execute this program three times, once unmodified,
  555. and twice with the suggested changes, then study the output to
  556. assure yourself that you understand it completely.
  557.  
  558.  
  559.  
  560. PROGRAMMING EXERCISES
  561. _________________________________________________________________
  562.  
  563. 1.   Move the end of the accept statement in HOTDOG.ADA to the line
  564.      immediately after the accept statement itself to see that it
  565.      is possible to eat the hot dog before it is made because the
  566.      tasks are both running at the same time.
  567.  
  568. 2.   Add another task to RETAIL2.ADA that executes a loop 10 times
  569.      with a 0.3 second delay that outputs the current number of hot
  570.      dogs on the shelf.
  571.  
  572. 3.   Using the package Calendar, output the elapsed time each time
  573.      the new procedure defined in exercise 2 outputs the number of
  574.      hot dogs on the shelf.
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.                                                        Page 25-10