Я работал над каким-то многопоточным сетевым кодом Ады, который включал в себя параллельный прием и обработку нескольких подключений. Идеальная ситуация для использования задач Ады, не так ли? В частности, несколько переменных типа задачи, запускаемые в цикле.
Ну, я сделал что-то вроде этого:
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;
Ожидая, что задачи, как только они примут запись start
, будут выполняться параллельно.
Однако, как и в этом примере, основная задача ждала завершения выполнения каждой задачи по очереди:
$ 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
Объявление всех задач заранее, в массиве, решило проблему, но оставило меня любопытным, как это на самом деле работает, почему и где это будет задокументировано.
ARM2012, раздел 9.2, абзац 6/3, мне кажется, говорит, что основной поток ожидает в конце выполнения завершения своих дочерних задач, но на практике он, кажется, ждет, когда задачи покинут текущую область, прежде чем продолжить выполнение (т.е. зацикливание вокруг и приступить к следующему заданию).
Это проблема компилятора, проблема документации или проблема кодирования?
Программа (обе версии) работает так, как говорит стандарт Ады. В версии, которую вы показываете, панель объекта задачи, объявляемая локально в объявлении .. begin .. end блока, зависит от этого блока (который является «мастером» задачи), и поэтому этот оператор блока ожидает задачи для завершения до продолжения выполнения (покидает оператор блока).
Часть RM, определяющая это, — раздел 9.3 «Зависимость от задачи — завершение задач», http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-9-3.html, в котором показан пример, близкий к вашему коду. Я не думаю, что пункт 6/3 в разделе 9.2 актуален - он описывает некоторые довольно частные случаи, в которых локально созданная задача никогда не активируется.
Решение, как вы нашли, состоит в том, чтобы объявить объекты задачи глобально, чтобы «мастер» жил дольше. В примере в разделе 9.3 показано другое решение, в котором используются типы доступа и динамически выделяемые объекты задач.
Что ж, это может быть намного яснее во вступлении к Аде от AdaCore и в викибуке. Спасибо!