home *** CD-ROM | disk | FTP | other *** search
-
-
-
- Chapter 24
- SIMPLE TASKING
-
-
- WHAT IS TASKING?
- _________________________________________________________________
-
- The topic of tasking is probably new to you regardless of what
- programming experience you have, because tasking is a relatively
- new technique which is not available with most programming
- languages. If you need some kind of a parallel operation with most
- other languages, you are required to use some rather tricky
- techniques or write a driver in assembly language. With Ada,
- however, tasking is designed into the language and is extremely
- easy to use.
-
-
- BUT NOT TRULY PARALLEL IN ADA
- _________________________________________________________________
-
- Tasking is the ability of the computer to appear to be doing two
- or more things at once even though it only has one processor. True
- parallel operation occurs when there actually are multiple
- processors available in the hardware, but since most modern
- computers have only one processor, we must make the system appear
- to have more than one by sharing the processor between two or more
- tasks. We will have much more to say about this later, but we must
- discuss another topic first.
-
-
- REAL-TIME REQUIRES TIMING
- _________________________________________________________________
-
- In the initial design of the Ada programming ===============
- language, a requirement was included that it be TIMER.ADA
- capable of operating in a real-time environment. ===============
- This requires that we have some control of time.
- We at least need the ability to read the current
- time and know when we arrive at some specified time. The example
- program named TIMER.ADA will illustrate how we can do just that.
-
- The program begins in our usual way except for the addition of the
- new package listed in line 3, the Calendar package which must be
- supplied with your compiler if you have a validated Ada compiler.
- The specification package for Calendar is listed in section 9.6 of
- the LRM and is probably listed somewhere in your compiler
- documentation. This package gives you the ability to read the
- system time and date, and allows you to set up a timed delay.
- Refer to a listing of the specification package of Calendar and
- follow along in the discussion in the next paragraph.
-
-
-
-
- Page 24-1
-
- Chapter 24 - Simple Tasking
-
- THE CLOCK FUNCTION
- _________________________________________________________________
-
- You will notice that the type TIME is private, so you cannot see
- how it is implemented, but you won't need to see it. A call to the
- function Clock returns the current time and date to a variable of
- type TIME, and other functions are provided to get the individual
- elements of the date or the number of seconds since midnight. You
- cannot read the individual elements directly, because some may
- change between subsequent reads leading to erroneous data. A
- procedure named Split is provided to split up the type TIME
- variable and return all four fields at once, and another is
- provided named Time_Of which will combine the individual elements
- into a TIME type variable when it is given the four elements as
- inputs.
-
- Finally, you are provided with several overloadings of the
- addition, subtraction, and some compare operators in order to
- effectively use the Calendar package. A single exception is
- declared which will be raised if you attempt to use one of these
- subprograms wrong.
-
-
- THE delay STATEMENT
- _________________________________________________________________
-
- The reserved word delay is used to indicate to the computer that
- you wish to include a delay at some point in the program. The
- delay is given in seconds as illustrated in line 19 of the program
- under study, and is declared as a fixed point number, which is
- defined by each implementation. The value of the delay is of type
- DAY_DURATION, but in this case, the universal_real type is used.
- The exact definition of the delay is given in appendix F of your
- compiler. It must allow a range of at least 0.0 to 86,400.0 which
- is the number of seconds in a day, and it must allow a delta of not
- more than 20 milliseconds. Refer to appendix F of your compiler
- documentation to see the exact declaration for this type for your
- particular compiler. The LRM requires that when the delay
- statement is encountered, the system must delay at the point of
- occurrence for at least the period specified in the delay
- statement, but does not say how much longer the system can delay.
- This leads to some inaccuracy in the delay which will be up to you
- to take care of. We will see how later in this example program.
-
- A fixed point variable is used for the delay variable so that
- addition of times can be done with no loss in accuracy, and fixed
- point numbers have a fixed accuracy.
-
- When you execute this program, you will see the first line
- displayed on the monitor, then a pause before the second message
- is displayed due to the delay statement in line 19. In fact, the
- pause will be at least 3.14 seconds according to the Ada
- specification.
-
-
- Page 24-2
-
- Chapter 24 - Simple Tasking
-
- USING THE CLOCK FUNCTION
- _________________________________________________________________
-
- In line 22, the Clock function is used to return the current time
- and date and assign it to the variable named Time_And_Date. In the
- next line we use the procedure named Split to split the time and
- date, which is contained in the composite variable named
- Time_And_Date, into its various components. Although the only
- component we are interested in is the Seconds field, we must
- provide a variable for each of the other fields simply because of
- the nature of the procedure call. Within the function call, we
- assign the value of Seconds to Start for later use. This is a
- record of the time when we started the loop which we will use
- later. The time is in the form of the number of seconds that have
- elapsed since midnight according to the definition of the calendar
- package.
-
- We execute a loop in lines 25 through 38 where we read the time and
- date, split it into its component parts, and display each of the
- components. Instead of displaying the time since midnight, we
- subtract the Start time from the current time in line 35, where we
- are actually using one of the overloadings from the Calendar
- package. We display the elapsed time since we executed line 22 of
- this program. Finally, we put in a total delay of one second each
- time we pass through the loop so we can see the delays accumulate.
-
-
- WE ARE ACCUMULATING ERRORS IN THIS LOOP
- _________________________________________________________________
-
- You will recall that the delay statement requires a delay of at
- least the amount listed, but says nothing of extra delay allowed
- when returning to the program, in order to give the compiler
- writers leeway in how to implement the delay statement. In
- addition, we will require some time to execute the other statements
- in the loop, so it should not be surprising to you that when you
- compile and execute this program, the time will not advance by
- exactly one second for each pass through the loop, but will precess
- slightly as time passes.
-
-
- A LOOP WITHOUT ERRORS
- _________________________________________________________________
-
- In lines 42 through 51, we essentially repeat the loop but with a
- slight difference. Instead of delaying for one second in each
- loop, we delay the amount needed to get to the desired point in
- time. In line 50, we convert the type of Index to DAY_DURATION
- with an explicit type conversion, then subtract the current elapsed
- time to calculate the desired time of the delay. This prevents an
- accumulation of error, and when you run the program you will see
- only the digitizing error introduced by the fixed point number.
- However, there is still one potential problem with this method.
-
-
- Page 24-3
-
- Chapter 24 - Simple Tasking
-
- WHAT IF A NEGATIVE DELAY IS REQUESTED?
- _________________________________________________________________
-
- When calculating delay times like this, it is possible for the
- required delay time to result in a negative number. The Ada
- designers had enough foresight to see that in most applications,
- you would desire to simply push forward, so they defined the delay
- such that a negative value for the delay time would be construed
- as a zero, and no error would be raised. If a negative time should
- be considered an error condition for your application, it is up to
- you to detect it and issue an appropriate error message, or raise
- an exception.
-
- Be sure to compile and execute this program and observe the output.
- Due to the delays in the first loop, the data output to the monitor
- is somewhat irregular and can be seen when the program is executed.
-
-
-
- THE delay IS NOT PART OF CALENDAR
- _________________________________________________________________
-
- One final point must be made before we leave this program. The
- Calendar package and the delay statement were both introduced here,
- and even though they work well together, they are completely
- separate. The delay statement is not a part of the Calendar
- package as will be evidenced in the example programs later in this
- chapter.
-
-
-
- OUR FIRST TASKING EXAMPLE
- _________________________________________________________________
-
- Examine the file named TASK1.ADA for an example ===============
- program containing some tasking. The first TASK1.ADA
- thing you should examine is the main program ===============
- consisting of a single executable statement in
- line 40 that outputs a line of text to the
- monitor. It may seem strange that it doesn't call any of the code
- in the declaration part, but it doesn't have to as we shall see.
-
- An Ada task is composed of a task specification and a task body,
- the former being illustrated in line 9, and the latter being
- illustrated in lines 10 through 17. This is the first task and
- both parts begin with the reserved word task. The structure of a
- task is very similar to the structure of a subprogram or package.
- This first example is a very simple task which executes a for loop
- containing output statements. The end result consists of four
- lines of text being displayed on the monitor.
-
-
-
-
-
- Page 24-4
-
- Chapter 24 - Simple Tasking
-
- THE TASK SPECIFICATION
- _________________________________________________________________
-
- The task specification can be much more involved than this one, but
- this is a good first example. The general structure for the task
- specification is given by;
-
- task <task-name> is
- <entry points>;
- end <task-name>;
-
- but if there are no entry points, then only the reserved word task
- is needed followed by the task name. As with the package, the task
- specification must come before the task body.
-
-
- THE TASK BODY
- _________________________________________________________________
-
- The task body begins with the reserved words task and body,
- followed by the task name, and the remainder of the structure is
- identical to that of a procedure. There is a declarative part
- where types, variables, subprograms, packages, and even other tasks
- can be declared, followed by the executable part which follows the
- same rules as those for a main program. In this case, there is no
- declarative part, only an executable part. When this task is
- executed, it will output four lines to the monitor and stop. We
- will say a little more about when it gets executed in a few
- minutes.
-
-
- TWO MORE TASKS
- _________________________________________________________________
-
- It should be clear to you that there are two additional tasks in
- this program, one in lines 19 through 27 and another in lines 29
- through 37, each with its respective task specification and task
- body. There are actually four tasks, because the main program is
- itself another task that will run in parallel with the three
- explicitly declared here. Since it is very critical that you
- understand the order of execution of the various tasks, we will
- spend some time defining it in detail.
-
- Ada always uses linear declaration and when it loads any program,
- it loads things in the order given in the listing. Therefore when
- it finds the task body beginning in line 10, it elaborates all of
- its declarations, although there are none in this case, then loads
- the executable part of the task, but does not begin execution yet.
- It effectively makes the task wait at the begin in line 11 until
- the other tasks are ready to begin execution. It does the same for
- the task named Second_Task, and also for Third_Task. When all
- declarations are elaborated it arrives at the begin of the main
- program in line 39. At this point, all four tasks are waiting at
- their respective begin statements, and all four tasks are permitted
-
- Page 24-5
-
- Chapter 24 - Simple Tasking
-
- to begin execution at the same time. All are of equal priority,
- but a strange thing happens when they begin execution.
-
-
- ORDER OF EXECUTION IS UNDEFINED BY ADA
- _________________________________________________________________
-
- The rules of execution, as defined by the LRM, give no requirements
- that any form of time slicing be done, nor is it illegal for an
- implementation to allow starving to occur. Starving is where one
- task uses all of the available time and the other task or tasks are
- allowed to starve because they receive no time for operation. In
- addition, there is no required order of execution concerning which
- of the four tasks in our example will execute first, because we
- have not included any form of priority. Because of these rules,
- we cannot predict exactly what your implementation will do, but can
- only give the results of executing this program on one particular
- validated Ada compiler. As indicated by the results of execution
- listed following the program, this particular compiler allows the
- task named Third_Task to utilize all computing power until it runs
- to completion, then Second_Task uses all of the resources, followed
- by First_Task, and finally the main program runs. Your particular
- compiler may execute these statements in a different order, but
- that is still correct. The only requirement is that all 17 lines
- be output in any order. Of course the order of output is defined
- within any task according to the rules of sequential operation.
- For example, pass number 2 of Third_Task must follow pass 1 of the
- same task.
-
-
- HOW DOES TASKING END?
- _________________________________________________________________
-
- When the task named Third_Task arrived at its end statement in line
- 17, it had executed all of its required statements and had nothing
- else to do, so it simply waited there until the other tasks were
- completed. When all four tasks, including the main program task,
- had arrived at their respective end statements, the Ada system knew
- there was nothing else to do, so it returned to the operating
- system as it does at any normal program completion.
-
- Because of the way this program operates, it is not clear that all
- four tasks are operating in parallel, but they actually are, as we
- will see in the next example program. Compile and execute this
- program and study the output from your compiler to see if it is
- different from that obtained as output from our compiler.
-
-
- ADDING DELAYS ADDS TO THE CLARITY OF OPERATION
- _________________________________________________________________
-
- Examine the next example program named TASK2.ADA and you will
- notice that delay statements are added within each of the loops.
- The delays were chosen to illustrate that each loop is actually
-
- Page 24-6
-
- Chapter 24 - Simple Tasking
-
- operating in parallel. The main program is ===============
- identical to the last program, if you ignore the TASK2.ADA
- commented out statements, and since the main ===============
- program has no delay prior to its output
- statement, it will be the first to output to the
- monitor. The main program will also be the first to complete its
- operation and will then patiently wait at its end statement until
- the other three tasks complete their jobs.
-
- Because of the differences in the delays, the three tasks will each
- complete their delays at different times and the output should be
- very predictable. If you examine the result of execution given at
- the end of the program, you will see that the three tasks actually
- are running in parallel as we stated earlier. It would be
- profitable for you to compile and execute this program so you can
- observe the output firsthand.
-
-
-
- WHAT ABOUT THE MAIN PROGRAM?
- _________________________________________________________________
-
- Return once again to the program named TASK2.ADA so we can examine
- the main program. You should remove the comment marks from the
- three statements in the main program so that it also contains a
- loop and a delay within each pass through the loop. When you
- compile and execute the program as modified, it will execute a
- delay prior to the first output, and will output a total of five
- lines to the monitor interlaced with the outputs of the other
- tasks. This should be a good indication to you that the main
- program is acting just like another task. Compile and execute this
- program, as modified, to see that the main program acts just like
- another task.
-
-
-
- A BLOCK CAN HAVE TASKS WITHIN IT
- _________________________________________________________________
-
- Examine the program named TASK3.ADA for an ===============
- example of a main program with tasks embedded TASK3.ADA
- within it. There is a block declared in the ===============
- main program in lines 13 through 46 which is
- executed inline just like any other block. This
- block however, has the same three tasks we have used in the
- previous programs embedded within it. You will notice that the
- order of declaration is different here, since the three task
- specifications are given together in lines 14 through 16, but this
- is perfectly legal and would be legal in the last two programs
- also. The only requirement is that the task specification must be
- given before the task body for each declaring task.
-
-
-
-
- Page 24-7
-
- Chapter 24 - Simple Tasking
-
- WHAT GOOD IS A DELAY OF ZERO?
- _________________________________________________________________
-
- You will notice that all of the delays are of zero time, which may
- lead you to ask why we should even bother to include the delays.
- Each time the system encounters a delay of any kind, it must look
- at each task to see if any of them have timed out and need to be
- exercised. When it does that, it may advance to the next task in
- order, but it may not. Which task will be selected as the next
- task is undefined by the Ada LRM, so any task can be executed next,
- including the one it is presently executing. The end result is
- that all four tasks, including the one in the executable part of
- the block, may be executed in a round robin fashion, and none of
- the tasks are starved. It would be perfectly legal for a single
- task to starve the others, according to the LRM, so if your
- compiler allows this, it is not an error. Tasking, as used in a
- real programming situation will not have this problem since
- additional constructs will be included as we will discuss in the
- next few chapters of this tutorial.
-
- In a manner similar to that in the other example programs, when all
- four tasks are at their end points, the block is completed, and the
- remaining statement is executed in the main program. Note
- carefully that the main program did not enter into the tasking that
- was executed within the block. The inline block was executed as
- another sequential statement as part of the main program. Thus
- line 11 was executed, then the block in lines 13 through 46 was
- executed. When all four tasks including the one within the block
- body were completed, the output statement in line 48 was allowed
- to execute.
-
- Compile and execute this program and study the results. Use the
- results to prove to yourself that the statements in lines 11 and
- 48 of the main program did not enter into the tasking.
-
-
- PROGRAMMING EXERCISES
- _________________________________________________________________
-
- 1. Write a procedure that can be called from anywhere in the
- program named TIMER.ADA that will use the Seconds field
- returned from the procedure named Split, and display the time
- of day in hours, minutes, and seconds. Call this procedure
- from a few places within the program.
-
- 2. Modify the program named TASK3.ADA to include the executable
- statements in lines 11 and 48 within loops, with delays, to
- prove that the statements are executed in a sequential fashion
- and do not enter into the tasking which is restricted to the
- block in lines 13 through 46.
-
-
- Page 24-8