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

  1.  
  2.  
  3.  
  4.                                                        Chapter 27
  5.                                         ADDITIONAL TASKING TOPICS
  6.  
  7.  
  8. We have covered most of the topics concerning tasking in the last
  9. three chapters, but there are a few more tasking themes that must
  10. be considered in order for you to use tasking to the fullest.  The
  11. topics in this chapter are definitely advanced tasking topics and
  12. you may wish to ignore some of this material until you have gained
  13. considerable experience in the use of Ada.  It would be worth your
  14. time to at least read through this material once to gain some
  15. exposure to it and to realize that these capabilities exist in the
  16. Ada programming language.
  17.  
  18.  
  19. THE TASK TYPE
  20. _________________________________________________________________
  21.  
  22. Examine the program named TASKTYPE.ADA for an    ================
  23. example of the task type in Ada.  This will seem   TASKTYPE.ADA
  24. like a very strange construct, but if you spend  ================
  25. time thinking about it, you will see that it
  26. does have a place in an Ada program, and it can
  27. be very useful.
  28.  
  29. In all previous programs with tasking, we have declared a task
  30. specification followed by a task body, but that is not the general
  31. case.  It is actually a shorthand notation for declaring tasking
  32. and is somewhat similar to an anonymous type.  The more general
  33. case of task definition is to declare a task type specification,
  34. then the task body, followed by a task that is of the declared
  35. type.  In fact, the task is declared in much the same way we have
  36. been declaring variables in Ada, the task name followed by a colon
  37. and the task type.  In the present program we declare the first
  38. task type specification in lines 7 and 8, and the corresponding
  39. task body in lines 16 through 22.  The task itself is declared in
  40. line 13 where Cow is declared to be of task type SHORT_LINE.  In
  41. fact, there are three tasks declared in this line, the other two
  42. being named Dog and Pig.
  43.  
  44.  
  45. WHAT DOES IT REALLY MEAN?
  46. _________________________________________________________________
  47.  
  48. If we declared a data type, then used the data type to declare
  49. three variables, you would have no trouble understanding what was
  50. happening, because you have been doing that all along in this
  51. tutorial.  It may be a little more difficult for you to understand,
  52. but we are doing the same thing with the task, except that we are
  53. declaring a type of a section of code, then generating and
  54. executing three copies of that code.  It is the same as if we
  55. declared a task specification named Cow that was identical to that
  56. given in lines 7 and 8, then a task body named Cow that was
  57.  
  58.                                                         Page 27-1
  59.  
  60.                            Chapter 27 - Additional Tasking Topics
  61.  
  62. identical to that given in lines 16 through 22, and did exactly the
  63. same thing for the other two tasks named Dog and Pig.  Instead of
  64. duplicating the code three times we declared a pattern for the task
  65. then told the system to run three copies of it.
  66.  
  67. The task itself is extremely simple, consisting of a loop with a
  68. zero delay, and a statement to output a message to the standard
  69. output device, the monitor.  The tasks themselves are declared in
  70. line 13 before the task body is declared, but this should pose no
  71. difficulty for you since we have used partial declaration of
  72. subprograms and types before.  You will recall that Ada is designed
  73. such that "small" declarations must all be declared before any
  74. subprogram or package bodies to keep the smaller entities near the
  75. beginning.  It would therefore be a compile error to move the task
  76. declarations given in line 13 after the task body declarations.
  77.  
  78. A fine point should be mentioned here.  A task type is always of
  79. limited private type, which means you can do no operations on it.
  80. Assignment and comparisons are not available with a limited private
  81. type, and it makes sense to prevent these operations with tasks.
  82.  
  83.  
  84. THERE ARE TWO TASK TYPES DECLARED
  85. _________________________________________________________________
  86.  
  87. In addition to the task type named SHORT_LINE, there is another
  88. named LONG_LINE similar to the first, which outputs only three
  89. lines until it completes, but outputs a much longer line of text.
  90. Two copies of this type are declared and executed.
  91.  
  92. The end result of all of this is the generation and execution of
  93. five tasks all running in parallel with no rendezvous between them
  94. except for the zero time delay statements as discussed in an
  95. earlier chapter.
  96.  
  97.  
  98.  
  99. WHEN DO THEY RUN?
  100. _________________________________________________________________
  101.  
  102. We discussed in an earlier chapter how each of the tasks got
  103. started running and this is no different.  When all five tasks have
  104. been completely elaborated and are all waiting at their respective
  105. begin statements, and when the main program arrives at its begin
  106. statement, then all of the tasks begin to execute.  Remember that
  107. there are six tasks counting the main program as a task.  Likewise,
  108. when all of the tasks, including the main program, reach their end
  109. points, an orderly termination is effected and the program ceases
  110. to execute, returning control to the operating system.
  111.  
  112. Compile and run this program and you will see that all five tasks
  113. do indeed run as described above.  Add a few additional tasks in
  114. lines 13 and 14 to see how easy it is to add additional tasks once
  115. the task type is completed.  It would be well worth your time to
  116.  
  117.                                                         Page 27-2
  118.  
  119.                            Chapter 27 - Additional Tasking Topics
  120.  
  121. study this program until you understand this material, because it
  122. will be used in the next few example programs.
  123.  
  124.  
  125. A TASK AS PART OF A RECORD
  126. _________________________________________________________________
  127.  
  128. It will not be illustrated here, but it is possible to declare a
  129. task type variable as part of a record.  Such a record can be used
  130. to declare a task variable along with a few other variables for use
  131. by the task.
  132.  
  133.  
  134. AN ARRAY OF TASKS
  135. _________________________________________________________________
  136.  
  137. Examine the program named TASKARRY.ADA for an    ================
  138. example of an array of task types.  This program   TASKARRY.ADA
  139. is identical to the last except for the addition ================
  140. of an array of tasks in line 13.  The task name
  141. Cow is declared to be an array of tasks named
  142. Cow(1), Cow(2), ... Cow(4), so there are four tasks of this type
  143. running concurrently when execution begins.  These four are in
  144. addition to the two of type LONG_LINE as in the previous program.
  145. Nothing more needs to be said about this program except for you to
  146. compile and execute it to see that you really do get all six tasks
  147. running in parallel with the task in the main program.  There are
  148. actually seven tasks running in parallel.  It would be a snap to
  149. increase the Cow array to 6 tasks and see nine running, the six in
  150. the array, the two which are the other type, and the main program.
  151.  
  152.  
  153.  
  154. A TASK ACCESS TYPE
  155. _________________________________________________________________
  156.  
  157. Examine the program named TASKACES.ADA for an    ================
  158. example of an access type which can be used to     TASKACES.ADA
  159. access a task.  Once we have the ability to      ================
  160. access a task through an access variable, we can
  161. also dynamically allocate a task and execute it.
  162. We will illustrate this operation in the present example program.
  163.  
  164. This program in nearly identical to the last two except that the
  165. variables named Elephant and Hippopotamus are not task type
  166. variables, but task access type variables because we declared the
  167. type LONG_POINT as an access variable in line thirteen.
  168.  
  169. When we execute this program, the three statically declared tasks
  170. begin executing when the main program does, but the two access type
  171. variables do nothing because they are simply access types that
  172. access nothing yet.  The main program outputs a line of text to the
  173. monitor, then dynamically allocates a copy of the task type
  174. LONG_LINE in line 37 and the new task begins executing.  Another
  175.  
  176.                                                         Page 27-3
  177.  
  178.                            Chapter 27 - Additional Tasking Topics
  179.  
  180. task is allocated and begins execution in line 38.  All five tasks
  181. will run to completion and there will be an orderly termination.
  182.  
  183. In this case, the main program is a parent task to the two
  184. dynamically allocated tasks and they are referred to as children
  185. tasks of the main program.
  186.  
  187.  
  188. WHEN DO THEY BEGIN EXECUTION?
  189. _________________________________________________________________
  190.  
  191. The biggest difference between this program and the previous two,
  192. involves when the respective tasks begin execution.  All of the
  193. statically declared tasks begin execution when the main program
  194. begins, but the dynamically allocated tasks begin execution when
  195. they are allocated.  This can be clearly seen by studying the
  196. result of execution of each of the three programs.  In the present
  197. program, the first output of each of the two allocated tasks is
  198. delayed considerably behind the first output of the statically
  199. declared tasks.
  200.  
  201. Be sure to compile and execute this program and compare the output
  202. of your compiler with that generated by the author's Ada compiler.
  203. It would be a simple matter for you to add a few more access
  204. variables and allocate additional tasks just to gain the
  205. experience.
  206.  
  207.  
  208. A VERY INEFFICIENT EXAMPLE OF TASKING
  209. _________________________________________________________________
  210.  
  211. The example program named PARALLEL.ADA is an     ================
  212. example of a very poor way to solve this           PARALLEL.ADA
  213. particular problem but is a meaningful example   ================
  214. of a tasking solution to a problem.  In this
  215. program we will declare eleven parallel tasks,
  216. start all eleven running, then retrieve the results of the eleven
  217. tasks.
  218.  
  219. We begin by declaring several types and variables, then declare a
  220. task specification in lines 20 through 23 with two entry points.
  221. Because the constant EMPLOYEES is declared as having the value 11,
  222. we declare 11 tasks in line 25, named Adding_Task(1),
  223. Adding_Task(2), ... Adding_Task(11), each of which will begin
  224. running when we begin execution of the main program.  The task
  225. body, given in lines 28 through 42, consists of a local variable,
  226. and two accept statements, with a few calculations between them.
  227.  
  228. The main program is the most interesting part of this program, but
  229. we need to get through the initialization code before we come to
  230. the interesting part.  The initialization code in lines 45 through
  231. 51, assigns values to the big array declared previously including
  232. a couple of funny data points which will show up in the results.
  233. Finally, we display a message that the array is filled.
  234.  
  235.                                                         Page 27-4
  236.  
  237.                            Chapter 27 - Additional Tasking Topics
  238.  
  239.  
  240. START ALL TASKS RUNNING
  241. _________________________________________________________________
  242.  
  243. The loop in lines 56 through 58 calls the eleven tasks at their
  244. first entry point and begins them executing so that they all are
  245. executing their respective for loops.  If you had a computer with
  246. a large number of actual processors, each task could be assigned
  247. to a separate processor and all calculations could be done
  248. concurrently.  In the present case of adding seven numbers, the
  249. calculations are trivial, but if each task required the performance
  250. of several million floating point operations, the time saved
  251. through the efficient use of parallel hardware could be very
  252. significant.  This program serves to illustrate the technique that
  253. could be used and is the most practical illustration of tasking to
  254. be demonstrated in this course.
  255.  
  256.  
  257. ALL TASKS ARE NOW COMPLETE
  258. _________________________________________________________________
  259.  
  260. The loop in lines 61 through 64 once again calls all eleven tasks
  261. one at a time at their final entry point where it requests that the
  262. result of the summation be returned.  All results are stored in the
  263. Weekly_Totals array, and the results are then displayed along with
  264. appropriate text.  You will notice, when you examine the result of
  265. execution, that employees numbered 2 and 3 have the funny data
  266. reflected in their totals.
  267.  
  268. The point of interest you should have gleaned from this program is
  269. that all eleven tasks were operating in parallel, with the main
  270. program being a twelfth task.  The logic of the main program
  271. requires concurrent tasks as opposed to eleven calls to a single
  272. subprogram.  Keep in mind that this would actually be a very poor
  273. way to program this particular problem.
  274.  
  275. Be sure to compile and execute this program on your system to
  276. verify that the results are the same.  After it does compile and
  277. execute correctly, change the number of employees to see how many
  278. tasks can be operated in parallel with your system.  You will
  279. probably not be limited by some arbitrary upper limit on the number
  280. of allowable tasks, imposed by your particular compiler, but by the
  281. amount of memory required for each task.
  282.  
  283.  
  284. PRIORITY OF TASKS
  285. _________________________________________________________________
  286.  
  287. The example program named PRIORITY.ADA contains  ================
  288. an example of establishing priority within         PRIORITY.ADA
  289. tasks.  The priority of tasks is indicated by    ================
  290. the use of the pragma named PRIORITY as
  291. illustrated in the task specifications and the
  292. declaration part of the main program.  An integer class variable
  293.  
  294.                                                         Page 27-5
  295.  
  296.                            Chapter 27 - Additional Tasking Topics
  297.  
  298. is included in the parentheses with the larger numbers indicating
  299. the higher priority or the most urgent tasks.  The range of
  300. allowable priorities are defined for your individual compiler in
  301. the System specification package definition as a subrange of
  302. INTEGER.  According to the LRM, a range of 0..0 is legal.  If your
  303. compiler only supports a single value for the priority, you will
  304. have to change the priorities in this program to the single value
  305. and you will, in effect, have no priority.
  306.  
  307. Compile and execute this program, then change the priorities and
  308. see what order of execution you can achieve.  It is important to
  309. realize that the LRM does not absolutely define how priorities will
  310. be handled, but it only gives a rather vague definition.
  311. Priorities should be used with care in a production program.
  312.  
  313.  
  314. A FAMILY OF ENTRIES
  315. _________________________________________________________________
  316.  
  317. The example program named FAMILY.ADA illustrates ================
  318. one more construct that can be used with the        FAMILY.ADA
  319. tasking rendezvous to achieve a user defined     ================
  320. priority structure.  In this case, there are
  321. three entry points which are very similar but
  322. have only a small difference between them.  An enumerated variable
  323. is declared and used as the discriminator between the three
  324. entries.  The only real advantage to using a family of entries is
  325. that they all use the same name and therefore add to the clarity
  326. of the resulting program.
  327.  
  328. The use of the family of entries is illustrated here and should be
  329. very easy for you to understand.  When you do, compile and execute
  330. this program and compare your output with that given in the result
  331. of execution section.
  332.  
  333.  
  334. PROGRAMMING EXERCISES
  335. _________________________________________________________________
  336.  
  337. 1.   Increase the size of the array in TASKARRY.ADA to see how big
  338.      you can make this array before the program no longer fits in
  339.      memory.  This will give you an idea of how many tasks can be
  340.      run at the same time with your system.
  341.  
  342. 2.   Add another access variable to TASKACES.ADA and initialize it
  343.      as a part of its declaration.  When will this task begin
  344.      execution?
  345.  
  346.  
  347.  
  348.  
  349.  
  350.                                                         Page 27-6