


                                                       Chapter 27
                                        ADDITIONAL TASKING TOPICS


We have covered most of the topics concerning tasking in the last
three chapters, but there are a few more tasking themes that must
be considered in order for you to use tasking to the fullest.  The
topics in this chapter are definitely advanced tasking topics and
you may wish to ignore some of this material until you have gained
considerable experience in the use of Ada.  It would be worth your
time to at least read through this material once to gain some
exposure to it and to realize that these capabilities exist in the
Ada programming language.


THE TASK TYPE
_________________________________________________________________

Examine the program named TASKTYPE.ADA for an    ================
example of the task type in Ada.  This will seem   TASKTYPE.ADA
like a very strange construct, but if you spend  ================
time thinking about it, you will see that it
does have a place in an Ada program, and it can
be very useful.

In all previous programs with tasking, we have declared a task
specification followed by a task body, but that is not the general
case.  It is actually a shorthand notation for declaring tasking
and is somewhat similar to an anonymous type.  The more general
case of task definition is to declare a task type specification,
then the task body, followed by a task that is of the declared
type.  In fact, the task is declared in much the same way we have
been declaring variables in Ada, the task name followed by a colon
and the task type.  In the present program we declare the first
task type specification in lines 7 and 8, and the corresponding
task body in lines 16 through 22.  The task itself is declared in
line 13 where Cow is declared to be of task type SHORT_LINE.  In
fact, there are three tasks declared in this line, the other two
being named Dog and Pig.


WHAT DOES IT REALLY MEAN?
_________________________________________________________________

If we declared a data type, then used the data type to declare
three variables, you would have no trouble understanding what was
happening, because you have been doing that all along in this
tutorial.  It may be a little more difficult for you to understand,
but we are doing the same thing with the task, except that we are
declaring a type of a section of code, then generating and
executing three copies of that code.  It is the same as if we
declared a task specification named Cow that was identical to that
given in lines 7 and 8, then a task body named Cow that was

                                                        Page 27-1

                           Chapter 27 - Additional Tasking Topics

identical to that given in lines 16 through 22, and did exactly the
same thing for the other two tasks named Dog and Pig.  Instead of
duplicating the code three times we declared a pattern for the task
then told the system to run three copies of it.

The task itself is extremely simple, consisting of a loop with a
zero delay, and a statement to output a message to the standard
output device, the monitor.  The tasks themselves are declared in
line 13 before the task body is declared, but this should pose no
difficulty for you since we have used partial declaration of
subprograms and types before.  You will recall that Ada is designed
such that "small" declarations must all be declared before any
subprogram or package bodies to keep the smaller entities near the
beginning.  It would therefore be a compile error to move the task
declarations given in line 13 after the task body declarations.

A fine point should be mentioned here.  A task type is always of
limited private type, which means you can do no operations on it.
Assignment and comparisons are not available with a limited private
type, and it makes sense to prevent these operations with tasks.


THERE ARE TWO TASK TYPES DECLARED
_________________________________________________________________

In addition to the task type named SHORT_LINE, there is another
named LONG_LINE similar to the first, which outputs only three
lines until it completes, but outputs a much longer line of text.
Two copies of this type are declared and executed.

The end result of all of this is the generation and execution of
five tasks all running in parallel with no rendezvous between them
except for the zero time delay statements as discussed in an
earlier chapter.



WHEN DO THEY RUN?
_________________________________________________________________

We discussed in an earlier chapter how each of the tasks got
started running and this is no different.  When all five tasks have
been completely elaborated and are all waiting at their respective
begin statements, and when the main program arrives at its begin
statement, then all of the tasks begin to execute.  Remember that
there are six tasks counting the main program as a task.  Likewise,
when all of the tasks, including the main program, reach their end
points, an orderly termination is effected and the program ceases
to execute, returning control to the operating system.

Compile and run this program and you will see that all five tasks
do indeed run as described above.  Add a few additional tasks in
lines 13 and 14 to see how easy it is to add additional tasks once
the task type is completed.  It would be well worth your time to

                                                        Page 27-2

                           Chapter 27 - Additional Tasking Topics

study this program until you understand this material, because it
will be used in the next few example programs.


A TASK AS PART OF A RECORD
_________________________________________________________________

It will not be illustrated here, but it is possible to declare a
task type variable as part of a record.  Such a record can be used
to declare a task variable along with a few other variables for use
by the task.


AN ARRAY OF TASKS
_________________________________________________________________

Examine the program named TASKARRY.ADA for an    ================
example of an array of task types.  This program   TASKARRY.ADA
is identical to the last except for the addition ================
of an array of tasks in line 13.  The task name
Cow is declared to be an array of tasks named
Cow(1), Cow(2), ... Cow(4), so there are four tasks of this type
running concurrently when execution begins.  These four are in
addition to the two of type LONG_LINE as in the previous program.
Nothing more needs to be said about this program except for you to
compile and execute it to see that you really do get all six tasks
running in parallel with the task in the main program.  There are
actually seven tasks running in parallel.  It would be a snap to
increase the Cow array to 6 tasks and see nine running, the six in
the array, the two which are the other type, and the main program.



A TASK ACCESS TYPE
_________________________________________________________________

Examine the program named TASKACES.ADA for an    ================
example of an access type which can be used to     TASKACES.ADA
access a task.  Once we have the ability to      ================
access a task through an access variable, we can
also dynamically allocate a task and execute it.
We will illustrate this operation in the present example program.

This program in nearly identical to the last two except that the
variables named Elephant and Hippopotamus are not task type
variables, but task access type variables because we declared the
type LONG_POINT as an access variable in line thirteen.

When we execute this program, the three statically declared tasks
begin executing when the main program does, but the two access type
variables do nothing because they are simply access types that
access nothing yet.  The main program outputs a line of text to the
monitor, then dynamically allocates a copy of the task type
LONG_LINE in line 37 and the new task begins executing.  Another

                                                        Page 27-3

                           Chapter 27 - Additional Tasking Topics

task is allocated and begins execution in line 38.  All five tasks
will run to completion and there will be an orderly termination.

In this case, the main program is a parent task to the two
dynamically allocated tasks and they are referred to as children
tasks of the main program.


WHEN DO THEY BEGIN EXECUTION?
_________________________________________________________________

The biggest difference between this program and the previous two,
involves when the respective tasks begin execution.  All of the
statically declared tasks begin execution when the main program
begins, but the dynamically allocated tasks begin execution when
they are allocated.  This can be clearly seen by studying the
result of execution of each of the three programs.  In the present
program, the first output of each of the two allocated tasks is
delayed considerably behind the first output of the statically
declared tasks.

Be sure to compile and execute this program and compare the output
of your compiler with that generated by the author's Ada compiler.
It would be a simple matter for you to add a few more access
variables and allocate additional tasks just to gain the
experience.


A VERY INEFFICIENT EXAMPLE OF TASKING
_________________________________________________________________

The example program named PARALLEL.ADA is an     ================
example of a very poor way to solve this           PARALLEL.ADA
particular problem but is a meaningful example   ================
of a tasking solution to a problem.  In this
program we will declare eleven parallel tasks,
start all eleven running, then retrieve the results of the eleven
tasks.

We begin by declaring several types and variables, then declare a
task specification in lines 20 through 23 with two entry points.
Because the constant EMPLOYEES is declared as having the value 11,
we declare 11 tasks in line 25, named Adding_Task(1),
Adding_Task(2), ... Adding_Task(11), each of which will begin
running when we begin execution of the main program.  The task
body, given in lines 28 through 42, consists of a local variable,
and two accept statements, with a few calculations between them.

The main program is the most interesting part of this program, but
we need to get through the initialization code before we come to
the interesting part.  The initialization code in lines 45 through
51, assigns values to the big array declared previously including
a couple of funny data points which will show up in the results.
Finally, we display a message that the array is filled.

                                                        Page 27-4

                           Chapter 27 - Additional Tasking Topics


START ALL TASKS RUNNING
_________________________________________________________________

The loop in lines 56 through 58 calls the eleven tasks at their
first entry point and begins them executing so that they all are
executing their respective for loops.  If you had a computer with
a large number of actual processors, each task could be assigned
to a separate processor and all calculations could be done
concurrently.  In the present case of adding seven numbers, the
calculations are trivial, but if each task required the performance
of several million floating point operations, the time saved
through the efficient use of parallel hardware could be very
significant.  This program serves to illustrate the technique that
could be used and is the most practical illustration of tasking to
be demonstrated in this course.


ALL TASKS ARE NOW COMPLETE
_________________________________________________________________

The loop in lines 61 through 64 once again calls all eleven tasks
one at a time at their final entry point where it requests that the
result of the summation be returned.  All results are stored in the
Weekly_Totals array, and the results are then displayed along with
appropriate text.  You will notice, when you examine the result of
execution, that employees numbered 2 and 3 have the funny data
reflected in their totals.

The point of interest you should have gleaned from this program is
that all eleven tasks were operating in parallel, with the main
program being a twelfth task.  The logic of the main program
requires concurrent tasks as opposed to eleven calls to a single
subprogram.  Keep in mind that this would actually be a very poor
way to program this particular problem.

Be sure to compile and execute this program on your system to
verify that the results are the same.  After it does compile and
execute correctly, change the number of employees to see how many
tasks can be operated in parallel with your system.  You will
probably not be limited by some arbitrary upper limit on the number
of allowable tasks, imposed by your particular compiler, but by the
amount of memory required for each task.


PRIORITY OF TASKS
_________________________________________________________________

The example program named PRIORITY.ADA contains  ================
an example of establishing priority within         PRIORITY.ADA
tasks.  The priority of tasks is indicated by    ================
the use of the pragma named PRIORITY as
illustrated in the task specifications and the
declaration part of the main program.  An integer class variable

                                                        Page 27-5

                           Chapter 27 - Additional Tasking Topics

is included in the parentheses with the larger numbers indicating
the higher priority or the most urgent tasks.  The range of
allowable priorities are defined for your individual compiler in
the System specification package definition as a subrange of
INTEGER.  According to the LRM, a range of 0..0 is legal.  If your
compiler only supports a single value for the priority, you will
have to change the priorities in this program to the single value
and you will, in effect, have no priority.

Compile and execute this program, then change the priorities and
see what order of execution you can achieve.  It is important to
realize that the LRM does not absolutely define how priorities will
be handled, but it only gives a rather vague definition.
Priorities should be used with care in a production program.


A FAMILY OF ENTRIES
_________________________________________________________________

The example program named FAMILY.ADA illustrates ================
one more construct that can be used with the        FAMILY.ADA
tasking rendezvous to achieve a user defined     ================
priority structure.  In this case, there are
three entry points which are very similar but
have only a small difference between them.  An enumerated variable
is declared and used as the discriminator between the three
entries.  The only real advantage to using a family of entries is
that they all use the same name and therefore add to the clarity
of the resulting program.

The use of the family of entries is illustrated here and should be
very easy for you to understand.  When you do, compile and execute
this program and compare your output with that given in the result
of execution section.


PROGRAMMING EXERCISES
_________________________________________________________________

1.   Increase the size of the array in TASKARRY.ADA to see how big
     you can make this array before the program no longer fits in
     memory.  This will give you an idea of how many tasks can be
     run at the same time with your system.

2.   Add another access variable to TASKACES.ADA and initialize it
     as a part of its declaration.  When will this task begin
     execution?





                                                        Page 27-6