[comp.lang.ada] Two Questions on tasking

madmats@elma.epfl.ch (Mats Weber) (03/31/89)

> Date: 29 Mar 89 09:16:26 GMT
> From: mcvax!hp4nl!uva!mel!hm@uunet.uu.net  (HansM)
> Subject: Two questions
>
> We are trying to understand Ada tasking and there are two things we fail to
> understand:
>
> 1. When an exception is raised and not handled in a task body, the task
>    is terminated and the exception is not further propagated, without
>    notice (11.4.1.8).  Why is this?

This is because the execution of the task is independent of its creator. If
the exception were propagated to the task's creator, the exception handler in
the creator could get exceptions from all tasks he has created.
For example, if task A creates A.B, A.C and A.D and A.B raises Exception_B
and A.C raises exception Exception_C, how would the handler in A deal with
them ?
The Ada rules on exceptions state that only one exception may be active in any
thread of execution.

>    Is there a way to invoke the kind of traceback that occurs when an
>    exception is propagated out of the main program?

This is system dependant. Some systems notify you when an unhandled exception
terminates a task, others don't.
If you want to be shure, add handlers to your tasks that notify you when they
terminate as the result of an exception (be careful with Text_IO being called
by multiple tasks, use semaphores).

> 2. When a task has completed its execution, termination is delayed until all
>    dependent tasks have terminated (9.4.6).  As a result, our program
>    fills up all memory with completed tasks unable to terminate.  Why is
>    this?  Can something be done about it (without altering task dependency)?

Termination of tasks is a high level concept used in the LRM and has nothing
to do with memory use and reclamation. I know some systems implement memory
deallocation for tasks very poorly. A good workaround is to reuse your tasks
as described in another reply.

The reason why a task's termination is delayed until all dependent tasks have
terminated can be seen in the following example:

procedure Main_Program is

   task T1;

   task T3;

   task body T1 is

      task T2;

      Local : Integer;

      task body T2 is
      begin
         ...
         Some_Action(Local);
         ...
      end T2;

   begin
      ...
   end T1;

   task body T3 is ...;

begin
   ...
end Main_Program;

If T1 completes before T2 terminates, it must wait for it because T2 may use
local items declared in T1. For the same reason, the main program must wait
for T1 and T3 to terminate. On the other hand, the termination of T1 and T3 is
independent.

Mats Weber
Swiss Federal Institute of Technology
EPFL DI LITh
1015 Lausanne
Switzerland

e-mail : madmats@elma.epfl.ch

rjh@cs.purdue.EDU (Bob Hathaway) (04/01/89)

In article <890331161111.20401e9f@elcc.epfl.ch> madmats@elma.epfl.ch (Mats Weber) writes:
>> 1. When an exception is raised and not handled in a task body, the task
>>    is terminated and the exception is not further propagated, without
>>    notice (11.4.1.8).  Why is this?
>
>This is because the execution of the task is independent of its creator.

According to section 9.4.1: "Each task depends on at least one master.".

>If the exception were propagated to the task's creator, the exception 
>handler in the creator could get exceptions from all tasks he has created.
>For example, if task A creates A.B, A.C and A.D and A.B raises Exception_B
>and A.C raises exception Exception_C, how would the handler in A deal with
>them ?
>The Ada rules on exceptions state that only one exception may be active in
>any thread of execution.

According to section 9.3.3, if any child task does not have a handler for 
a raised exception, the exception TASKING_ERROR is propagated to the master
upon conclusion of the activation of all sibling tasks and is propagated
to the master only once for any number of concluded child tasks.  What is 
being asserted above? 

Bob Hathaway
rjh@purdue.edu

madmats@elma.epfl.ch (Mats Weber) (04/03/89)

Bob Hathaway (rjh@purdue.edu) writes :

>>This is because the execution of the task is independent of its creator.

> According to section 9.4.1: "Each task depends on at least one master.".

True, but the dependence on a master is for task termination.
What I meant by "the execution of the task is independent of its creator" was
that the task and its creator are two different threads of execution.

>>If the exception were propagated to the task's creator, the exception
>>handler in the creator could get exceptions from all tasks he has created.
>>For example, if task A creates A.B, A.C and A.D and A.B raises Exception_B
>>and A.C raises exception Exception_C, how would the handler in A deal with
>>them ?
>>The Ada rules on exceptions state that only one exception may be active in
>>any thread of execution.

>According to section 9.3.3, if any child task does not have a handler for
>a raised exception, the exception TASKING_ERROR is propagated to the master
>upon conclusion of the activation of all sibling tasks and is propagated
>to the master only once for any number of concluded child tasks.  What is
>being asserted above?

TASKING_ERROR is propagated to the master if an exception is
raised during the activation (that is, the elaboration of the declarative part)
of any child task, not otherwise.

- Handlers in the child task do not apply to exceptions raised
  in its declarative part, just like in other blocks.
- If an exception is raised in the child task after completion of its
  activation (that is, after the reserved word begin of the child task),
  then this exception is not propagated outside the child task even if the
  child task does not handle it (the exception gets lost, unnoticed, and the
  child task becomes completed).
- What is being asserted above is what Scott Simpson
  (trwarcadia!simpson@oberon.usc.edu) says more clearly in his message, i.e.
  that if the language design would have incorporated exception propagation
  from already activated children tasks to their direct master, there would
  be asynchronous communication between the tasks. Moreover, if a given master
  has two or more child tasks, then several exceptions might be raised
  simultaneously in the master's thread of execution.
- The master waits for the completion of the activation of all its children
  before he (the master) begins executing its own sequence of statements.
  This waiting makes it possible for Tasking_Error to be raised at a well
  defined point in the master (just before its first statement).

Mats Weber
Swiss Federal Institute of Technology
EPFL DI LITh
1015 Lausanne
Switzerland

e-mail : madmats@elma.epfl.ch

NCOHEN@IBM.COM (Norman Cohen) (04/03/89)

Ref: INFO-ADA Digest Volume 89 Issue 96 (Sat, Apr 1, 1989) Item #5

Bob Hathaway writes:

>According to section 9.3.3, if any child task does not have a handler
>for a raised exception, the exception TASKING_ERROR is propagated to the
>master upon conclusion of the activation of all sibling tasks and is
>propagated to the master only once for any number of concluded child
>tasks.  What is being asserted above?

Paragraph 9.3(3) refers to exceptions arising during the ACTIVATION of
a task.  Activation is defined in 9.3(1) as follows:

   The initial part of this execution [of a task body] is called the
   _activation_ of the task object, and also that of the designated
   task; it consists of of the elaboration of the declarative part, if
   any, of the task body.

To understand the rules given in paragraphs 9.3(2) and 9.3(3), consider
the following example:

   declare
      A, B : Some_Task_Type;
      C : array (1 .. 10) of Some_Task_Type;
   begin
      -- (*)
      S;
   end;

(Some_Task_Type is some task type.)  Twelve task objects (A, B and
C(1) through C(10)) are declared in the declarative part of the block
statement.  The following events occur:

  1. After the task executing the block statement reaches the point
     marked (*), the task pauses, and twelve new tasks are now created
     to be designated by the twelve declared task objects.

  2. Each of these twelve new tasks asynchronously executes the
     declarative part of the Some_Task_Type task body (or dies trying).

  3. THE TWELVE NEW TASKS AND THE TASK EXECUTING THE BLOCK STATEMENT ALL
     SYNCHRONIZE.  If one or more of the twelve new tasks died trying to
     elaborate its declarative part (i.e., raised an exception),
     TASKING_ERROR is raised (once) in the block statement, at point (*).
     Otherwise, after synchronizing, the twelve new tasks and the task
     executing the block statement begin asynchronous execution (with
     execution of the block statement resuming at point (*)).

If any of the twelve new tasks raises an unhandled exception AFTER this
synchronization point, no exception is propagated to the task executing
the block statement.

Norman Cohen