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

  1.  
  2.  
  3.  
  4.                                                        Chapter 24
  5.                                                    SIMPLE TASKING
  6.  
  7.  
  8. WHAT IS TASKING?
  9. _________________________________________________________________
  10.  
  11. The topic of tasking is probably new to you regardless of what
  12. programming experience you have, because tasking is a relatively
  13. new technique which is not available with most programming
  14. languages.  If you need some kind of a parallel operation with most
  15. other languages, you are required to use some rather tricky
  16. techniques or write a driver in assembly language.  With Ada,
  17. however, tasking is designed into the language and is extremely
  18. easy to use.
  19.  
  20.  
  21. BUT NOT TRULY PARALLEL IN ADA
  22. _________________________________________________________________
  23.  
  24. Tasking is the ability of the computer to appear to be doing two
  25. or more things at once even though it only has one processor.  True
  26. parallel operation occurs when there actually are multiple
  27. processors available in the hardware, but since most modern
  28. computers have only one processor, we must make the system appear
  29. to have more than one by sharing the processor between two or more
  30. tasks.  We will have much more to say about this later, but we must
  31. discuss another topic first.
  32.  
  33.  
  34. REAL-TIME REQUIRES TIMING
  35. _________________________________________________________________
  36.  
  37. In the initial design of the Ada programming      ===============
  38. language, a requirement was included that it be      TIMER.ADA
  39. capable of operating in a real-time environment.  ===============
  40. This requires that we have some control of time.
  41. We at least need the ability to read the current
  42. time and know when we arrive at some specified time.  The example
  43. program named TIMER.ADA will illustrate how we can do just that.
  44.  
  45. The program begins in our usual way except for the addition of the
  46. new package listed in line 3, the Calendar package which must be
  47. supplied with your compiler if you have a validated Ada compiler.
  48. The specification package for Calendar is listed in section 9.6 of
  49. the LRM and is probably listed somewhere in your compiler
  50. documentation.  This package gives you the ability to read the
  51. system time and date, and allows you to set up a timed delay.
  52. Refer to a listing of the specification package of Calendar and
  53. follow along in the discussion in the next paragraph.
  54.  
  55.  
  56.  
  57.  
  58.                                                         Page 24-1
  59.  
  60.                                       Chapter 24 - Simple Tasking
  61.  
  62. THE CLOCK FUNCTION
  63. _________________________________________________________________
  64.  
  65. You will notice that the type TIME is private, so you cannot see
  66. how it is implemented, but you won't need to see it.  A call to the
  67. function Clock returns the current time and date to a variable of
  68. type TIME, and other functions are provided to get the individual
  69. elements of the date or the number of seconds since midnight.  You
  70. cannot read the individual elements directly, because some may
  71. change between subsequent reads leading to erroneous data.  A
  72. procedure named Split is provided to split up the type TIME
  73. variable and return all four fields at once, and another is
  74. provided named Time_Of which will combine the individual elements
  75. into a TIME type variable when it is given the four elements as
  76. inputs.
  77.  
  78. Finally, you are provided with several overloadings of the
  79. addition, subtraction, and some compare operators in order to
  80. effectively use the Calendar package.  A single exception is
  81. declared which will be raised if you attempt to use one of these
  82. subprograms wrong.
  83.  
  84.  
  85. THE delay STATEMENT
  86. _________________________________________________________________
  87.  
  88. The reserved word delay is used to indicate to the computer that
  89. you wish to include a delay at some point in the program.  The
  90. delay is given in seconds as illustrated in line 19 of the program
  91. under study, and is declared as a fixed point number, which is
  92. defined by each implementation.  The value of the delay is of type
  93. DAY_DURATION, but in this case, the universal_real type is used.
  94. The exact definition of the delay is given in appendix F of your
  95. compiler.  It must allow a range of at least 0.0 to 86,400.0 which
  96. is the number of seconds in a day, and it must allow a delta of not
  97. more than 20 milliseconds.  Refer to appendix F of your compiler
  98. documentation to see the exact declaration for this type for your
  99. particular compiler.  The LRM requires that when the delay
  100. statement is encountered, the system must delay at the point of
  101. occurrence for at least the period specified in the delay
  102. statement, but does not say how much longer the system can delay.
  103. This leads to some inaccuracy in the delay which will be up to you
  104. to take care of.  We will see how later in this example program.
  105.  
  106. A fixed point variable is used for the delay variable so that
  107. addition of times can be done with no loss in accuracy, and fixed
  108. point numbers have a fixed accuracy.
  109.  
  110. When you execute this program, you will see the first line
  111. displayed on the monitor, then a pause before the second message
  112. is displayed due to the delay statement in line 19.  In fact, the
  113. pause will be at least 3.14 seconds according to the Ada
  114. specification.
  115.  
  116.  
  117.                                                         Page 24-2
  118.  
  119.                                       Chapter 24 - Simple Tasking
  120.  
  121. USING THE CLOCK FUNCTION
  122. _________________________________________________________________
  123.  
  124. In line 22, the Clock function is used to return the current time
  125. and date and assign it to the variable named Time_And_Date.  In the
  126. next line we use the procedure named Split to split the time and
  127. date, which is contained in the composite variable named
  128. Time_And_Date, into its various components.  Although the only
  129. component we are interested in is the Seconds field, we must
  130. provide a variable for each of the other fields simply because of
  131. the nature of the procedure call.  Within the function call, we
  132. assign the value of Seconds to Start for later use.  This is a
  133. record of the time when we started the loop which we will use
  134. later.  The time is in the form of the number of seconds that have
  135. elapsed since midnight according to the definition of the calendar
  136. package.
  137.  
  138. We execute a loop in lines 25 through 38 where we read the time and
  139. date, split it into its component parts, and display each of the
  140. components.  Instead of displaying the time since midnight, we
  141. subtract the Start time from the current time in line 35, where we
  142. are actually using one of the overloadings from the Calendar
  143. package.  We display the elapsed time since we executed line 22 of
  144. this program.  Finally, we put in a total delay of one second each
  145. time we pass through the loop so we can see the delays accumulate.
  146.  
  147.  
  148. WE ARE ACCUMULATING ERRORS IN THIS LOOP
  149. _________________________________________________________________
  150.  
  151. You will recall that the delay statement requires a delay of at
  152. least the amount listed, but says nothing of extra delay allowed
  153. when returning to the program, in order to give the compiler
  154. writers leeway in how to implement the delay statement.  In
  155. addition, we will require some time to execute the other statements
  156. in the loop, so it should not be surprising to you that when you
  157. compile and execute this program, the time will not advance by
  158. exactly one second for each pass through the loop, but will precess
  159. slightly as time passes.
  160.  
  161.  
  162. A LOOP WITHOUT ERRORS
  163. _________________________________________________________________
  164.  
  165. In lines 42 through 51, we essentially repeat the loop but with a
  166. slight difference.  Instead of delaying for one second in each
  167. loop, we delay the amount needed to get to the desired point in
  168. time.  In line 50, we convert the type of Index to DAY_DURATION
  169. with an explicit type conversion, then subtract the current elapsed
  170. time to calculate the desired time of the delay.  This prevents an
  171. accumulation of error, and when you run the program you will see
  172. only the digitizing error introduced by the fixed point number.
  173. However, there is still one potential problem with this method.
  174.  
  175.  
  176.                                                         Page 24-3
  177.  
  178.                                       Chapter 24 - Simple Tasking
  179.  
  180. WHAT IF A NEGATIVE DELAY IS REQUESTED?
  181. _________________________________________________________________
  182.  
  183. When calculating delay times like this, it is possible for the
  184. required delay time to result in a negative number.  The Ada
  185. designers had enough foresight to see that in most applications,
  186. you would desire to simply push forward, so they defined the delay
  187. such that a negative value for the delay time would be construed
  188. as a zero, and no error would be raised.  If a negative time should
  189. be considered an error condition for your application, it is up to
  190. you to detect it and issue an appropriate error message, or raise
  191. an exception.
  192.  
  193. Be sure to compile and execute this program and observe the output.
  194. Due to the delays in the first loop, the data output to the monitor
  195. is somewhat irregular and can be seen when the program is executed.
  196.  
  197.  
  198.  
  199. THE delay IS NOT PART OF CALENDAR
  200. _________________________________________________________________
  201.  
  202. One final point must be made before we leave this program.  The
  203. Calendar package and the delay statement were both introduced here,
  204. and even though they work well together, they are completely
  205. separate.  The delay statement is not a part of the Calendar
  206. package as will be evidenced in the example programs later in this
  207. chapter.
  208.  
  209.  
  210.  
  211. OUR FIRST TASKING EXAMPLE
  212. _________________________________________________________________
  213.  
  214. Examine the file named TASK1.ADA for an example   ===============
  215. program containing some tasking.  The first          TASK1.ADA
  216. thing you should examine is the main program      ===============
  217. consisting of a single executable statement in
  218. line 40 that outputs a line of text to the
  219. monitor.  It may seem strange that it doesn't call any of the code
  220. in the declaration part, but it doesn't have to as we shall see.
  221.  
  222. An Ada task is composed of a task specification and a task body,
  223. the former being illustrated in line 9, and the latter being
  224. illustrated in lines 10 through 17.  This is the first task and
  225. both parts begin with the reserved word task.  The structure of a
  226. task is very similar to the structure of a subprogram or package.
  227. This first example is a very simple task which executes a for loop
  228. containing output statements.  The end result consists of four
  229. lines of text being displayed on the monitor.
  230.  
  231.  
  232.  
  233.  
  234.  
  235.                                                         Page 24-4
  236.  
  237.                                       Chapter 24 - Simple Tasking
  238.  
  239. THE TASK SPECIFICATION
  240. _________________________________________________________________
  241.  
  242. The task specification can be much more involved than this one, but
  243. this is a good first example.  The general structure for the task
  244. specification is given by;
  245.  
  246.      task <task-name> is
  247.            <entry points>;
  248.      end <task-name>;
  249.  
  250. but if there are no entry points, then only the reserved word task
  251. is needed followed by the task name.  As with the package, the task
  252. specification must come before the task body.
  253.  
  254.  
  255. THE TASK BODY
  256. _________________________________________________________________
  257.  
  258. The task body begins with the reserved words task and body,
  259. followed by the task name, and the remainder of the structure is
  260. identical to that of a procedure.  There is a declarative part
  261. where types, variables, subprograms, packages, and even other tasks
  262. can be declared, followed by the executable part which follows the
  263. same rules as those for a main program.  In this case, there is no
  264. declarative part, only an executable part.  When this task is
  265. executed, it will output four lines to the monitor and stop.  We
  266. will say a little more about when it gets executed in a few
  267. minutes.
  268.  
  269.  
  270. TWO MORE TASKS
  271. _________________________________________________________________
  272.  
  273. It should be clear to you that there are two additional tasks in
  274. this program, one in lines 19 through 27 and another in lines 29
  275. through 37, each with its respective task specification and task
  276. body.  There are actually four tasks, because the main program is
  277. itself another task that will run in parallel with the three
  278. explicitly declared here.  Since it is very critical that you
  279. understand the order of execution of the various tasks, we will
  280. spend some time defining it in detail.
  281.  
  282. Ada always uses linear declaration and when it loads any program,
  283. it loads things in the order given in the listing.  Therefore when
  284. it finds the task body beginning in line 10, it elaborates all of
  285. its declarations, although there are none in this case, then loads
  286. the executable part of the task, but does not begin execution yet.
  287. It effectively makes the task wait at the begin in line 11 until
  288. the other tasks are ready to begin execution.  It does the same for
  289. the task named Second_Task, and also for Third_Task.  When all
  290. declarations are elaborated it arrives at the begin of the main
  291. program in line 39.  At this point, all four tasks are waiting at
  292. their respective begin statements, and all four tasks are permitted
  293.  
  294.                                                         Page 24-5
  295.  
  296.                                       Chapter 24 - Simple Tasking
  297.  
  298. to begin execution at the same time.  All are of equal priority,
  299. but a strange thing happens when they begin execution.
  300.  
  301.  
  302. ORDER OF EXECUTION IS UNDEFINED BY ADA
  303. _________________________________________________________________
  304.  
  305. The rules of execution, as defined by the LRM, give no requirements
  306. that any form of time slicing be done, nor is it illegal for an
  307. implementation to allow starving to occur.  Starving is where one
  308. task uses all of the available time and the other task or tasks are
  309. allowed to starve because they receive no time for operation.  In
  310. addition, there is no required order of execution concerning which
  311. of the four tasks in our example will execute first, because we
  312. have not included any form of priority.  Because of these rules,
  313. we cannot predict exactly what your implementation will do, but can
  314. only give the results of executing this program on one particular
  315. validated Ada compiler.  As indicated by the results of execution
  316. listed following the program, this particular compiler allows the
  317. task named Third_Task to utilize all computing power until it runs
  318. to completion, then Second_Task uses all of the resources, followed
  319. by First_Task, and finally the main program runs.  Your particular
  320. compiler may execute these statements in a different order, but
  321. that is still correct.  The only requirement is that all 17 lines
  322. be output in any order.  Of course the order of output is defined
  323. within any task according to the rules of sequential operation.
  324. For example, pass number 2 of Third_Task must follow pass 1 of the
  325. same task.
  326.  
  327.  
  328. HOW DOES TASKING END?
  329. _________________________________________________________________
  330.  
  331. When the task named Third_Task arrived at its end statement in line
  332. 17, it had executed all of its required statements and had nothing
  333. else to do, so it simply waited there until the other tasks were
  334. completed.  When all four tasks, including the main program task,
  335. had arrived at their respective end statements, the Ada system knew
  336. there was nothing else to do, so it returned to the operating
  337. system as it does at any normal program completion.
  338.  
  339. Because of the way this program operates, it is not clear that all
  340. four tasks are operating in parallel, but they actually are, as we
  341. will see in the next example program.  Compile and execute this
  342. program and study the output from your compiler to see if it is
  343. different from that obtained as output from our compiler.
  344.  
  345.  
  346. ADDING DELAYS ADDS TO THE CLARITY OF OPERATION
  347. _________________________________________________________________
  348.  
  349. Examine the next example program named TASK2.ADA and you will
  350. notice that delay statements are added within each of the loops.
  351. The delays were chosen to illustrate that each loop is actually
  352.  
  353.                                                         Page 24-6
  354.  
  355.                                       Chapter 24 - Simple Tasking
  356.  
  357. operating in parallel.  The main program is       ===============
  358. identical to the last program, if you ignore the     TASK2.ADA
  359. commented out statements, and since the main      ===============
  360. program has no delay prior to its output
  361. statement, it will be the first to output to the
  362. monitor.  The main program will also be the first to complete its
  363. operation and will then patiently wait at its end statement until
  364. the other three tasks complete their jobs.
  365.  
  366. Because of the differences in the delays, the three tasks will each
  367. complete their delays at different times and the output should be
  368. very predictable.  If you examine the result of execution given at
  369. the end of the program, you will see that the three tasks actually
  370. are running in parallel as we stated earlier.  It would be
  371. profitable for you to compile and execute this program so you can
  372. observe the output firsthand.
  373.  
  374.  
  375.  
  376. WHAT ABOUT THE MAIN PROGRAM?
  377. _________________________________________________________________
  378.  
  379. Return once again to the program named TASK2.ADA so we can examine
  380. the main program.  You should remove the comment marks from the
  381. three statements in the main program so that it also contains a
  382. loop and a delay within each pass through the loop.  When you
  383. compile and execute the program as modified, it will execute a
  384. delay prior to the first output, and will output a total of five
  385. lines to the monitor interlaced with the outputs of the other
  386. tasks.  This should be a good indication to you that the main
  387. program is acting just like another task.  Compile and execute this
  388. program, as modified, to see that the main program acts just like
  389. another task.
  390.  
  391.  
  392.  
  393. A BLOCK CAN HAVE TASKS WITHIN IT
  394. _________________________________________________________________
  395.  
  396. Examine the program named TASK3.ADA for an        ===============
  397. example of a main program with tasks embedded        TASK3.ADA
  398. within it.  There is a block declared in the      ===============
  399. main program in lines 13 through 46 which is
  400. executed inline just like any other block.  This
  401. block however, has the same three tasks we have used in the
  402. previous programs embedded within it.  You will notice that the
  403. order of declaration is different here, since the three task
  404. specifications are given together in lines 14 through 16, but this
  405. is perfectly legal and would be legal in the last two programs
  406. also.  The only requirement is that the task specification must be
  407. given before the task body for each declaring task.
  408.  
  409.  
  410.  
  411.  
  412.                                                         Page 24-7
  413.  
  414.                                       Chapter 24 - Simple Tasking
  415.  
  416. WHAT GOOD IS A DELAY OF ZERO?
  417. _________________________________________________________________
  418.  
  419. You will notice that all of the delays are of zero time, which may
  420. lead you to ask why we should even bother to include the delays.
  421. Each time the system encounters a delay of any kind, it must look
  422. at each task to see if any of them have timed out and need to be
  423. exercised.  When it does that, it may advance to the next task in
  424. order, but it may not.  Which task will be selected as the next
  425. task is undefined by the Ada LRM, so any task can be executed next,
  426. including the one it is presently executing.  The end result is
  427. that all four tasks, including the one in the executable part of
  428. the block, may be executed in a round robin fashion, and none of
  429. the tasks are starved.  It would be perfectly legal for a single
  430. task to starve the others, according to the LRM, so if your
  431. compiler allows this, it is not an error.  Tasking, as used in a
  432. real programming situation will not have this problem since
  433. additional constructs will be included as we will discuss in the
  434. next few chapters of this tutorial.
  435.  
  436. In a manner similar to that in the other example programs, when all
  437. four tasks are at their end points, the block is completed, and the
  438. remaining statement is executed in the main program.  Note
  439. carefully that the main program did not enter into the tasking that
  440. was executed within the block.  The inline block was executed as
  441. another sequential statement as part of the main program.  Thus
  442. line 11 was executed, then the block in lines 13 through 46 was
  443. executed.  When all four tasks including the one within the block
  444. body were completed, the output statement in line 48 was allowed
  445. to execute.
  446.  
  447. Compile and execute this program and study the results.  Use the
  448. results to prove to yourself that the statements in lines 11 and
  449. 48 of the main program did not enter into the tasking.
  450.  
  451.  
  452. PROGRAMMING EXERCISES
  453. _________________________________________________________________
  454.  
  455. 1.   Write a procedure that can be called from anywhere in the
  456.      program named TIMER.ADA that will use the Seconds field
  457.      returned from the procedure named Split, and display the time
  458.      of day in hours, minutes, and seconds.  Call this procedure
  459.      from a few places within the program.
  460.  
  461. 2.   Modify the program named TASK3.ADA to include the executable
  462.      statements in lines 11 and 48 within loops, with delays, to
  463.      prove that the statements are executed in a sequential fashion
  464.      and do not enter into the tasking which is restricted to the
  465.      block in lines 13 through 46.
  466.  
  467.  
  468.                                                         Page 24-8