I was working on some multithreaded Ada network code, which involved accepting and handling multiple connections in parallel. An ideal situation for the use of Ada tasks, no? Specifically, multiple task type variables, started in a loop.
Well, I did something like this:
with Ada.Text_IO;
use Ada.Text_IO;
Procedure foo is
task type handler is
entry Start(I: Integer);
end handler;
task body handler is
task_index: Integer;
begin
accept Start(I: Integer) do
task_index:=I;
end Start;
for I in 1..5 loop
Put_Line("Task "&task_index'Image&": "&I'Image);
end loop;
end handler;
begin -- foo
for t in 1..5 loop
declare
bar: handler;
begin
bar.Start(t);
end;
end loop;
end foo;
Expecting that the tasks, once they accepted the start entry, would execute in parallel.
However, as in this example, the main task waited for each task to finish executing in turn:
$ gnat make foo
$ ./foo
Task 1: 1
Task 1: 2
Task 1: 3
Task 1: 4
Task 1: 5
Task 2: 1
Task 2: 2
Task 2: 3
Task 2: 4
Task 2: 5
Task 3: 1
Task 3: 2
Task 3: 3
Task 3: 4
Task 3: 5
Task 4: 1
Task 4: 2
Task 4: 3
Task 4: 4
Task 4: 5
Task 5: 1
Task 5: 2
Task 5: 3
Task 5: 4
Task 5: 5
Declaring all the tasks up-front, in an array fixed the issue, but left me curious about how this is actually working, why, and where this would be documented.
ARM2012 section 9.2 paragraph 6/3 seems to me to say that the main thread waits at the end of execution for it's child tasks to finish, but in practice it seems to be waiting when the tasks leave the current scope before continuing execution (i.e. looping around, and starting the next task).
Is this a compiler issue, a documentation issue, or a coding issue?