Можем ли мы выполнить каждую задачу из пула не синхронно? - PullRequest
0 голосов
/ 01 марта 2019

Я новичок в Ada.

Я объявил новый тип задачи и сохранил три из них в пуле.Затем я хочу запустить каждую задачу в цикле.

Ожидаемое поведение - все они выполняются одновременно.

Реальность такова, что они выполняются один за другим.другой.Таким образом, задачи (2) выполняются не раньше, чем задачи (1) завершаются.Фактически, задание (2) никогда не будет выполнено, поскольку оно заканчивается из-за ограничений выбора.

Мой код:

with Counter;
procedure Main is
    task type CounterTask is
        entry Execute(t:in Counter.Timeout; d:in Duration);
    end CounterTask;

    task body CounterTask is
        begin MyLoop: loop 
            select
                accept Execute(t:in Counter.Timeout;d:in Duration) do
                    Counter.Run(t, d);
                end Execute;
            or
                delay 2.0;
                exit;
            end select;
        end loop MyLoop;
    end CounterTask;
    tasks:Array(1..3) of CounterTask;
begin
    for i in Integer range 1..3 loop
        tasks(i).Execute(Counter.Timeout(10*i), Duration(0.5 * i));
    end loop;
end Main;

Любые подсказки или идеи будут приветствоваться!

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Помимо извлечения Counter.Run из блока accept (как было только что заявлено Саймоном Райтом), вы также можете рассмотреть возможность использования барьера синхронизации (см. Также ARM D.10.1 ):

with Counter;
with Ada.Synchronous_Barriers;

procedure Main is

  use Ada.Synchronous_Barriers;

  Num_Tasks : Positive := 3;

  Sync : Synchronous_Barrier (Num_Tasks);

  task type Counter_Task is
      entry Execute (T : in Counter.Timeout; D : in Duration);
  end Counter_Task;

  task body Counter_Task is
      Notified     : Boolean;
      The_Timeout  : Counter.Timeout;
      The_Duration : Duration;
  begin
      MyLoop : loop
        select

            accept Execute (T : in Counter.Timeout; D : in Duration) do
              The_Timeout  := T;
              The_Duration := D;
            end Execute;

            --  Synchronize tasks: wait until all 3 tasks have arrived at this point.
            Wait_For_Release (Sync, Notified);

            Counter.Run (The_Timeout, The_Duration);    
        or
            delay 2.0;
            exit;
        end select;
      end loop MyLoop;
  end Counter_Task;

  Tasks : array (1 .. Num_Tasks) of Counter_Task;

begin
  for K in Tasks'Range loop
      Tasks (K).Execute
        (Counter.Timeout (K * 10),
         Duration (Duration (0.5) * K));
  end loop;
end Main;
0 голосов
/ 02 марта 2019

Когда ваша основная программа вызывает оператор accept

accept Execute(t:in Counter.Timeout;d:in Duration) do
   Counter.Run(t, d);
end Execute;

, она блокируется до end Execute.Вы не показываете Counter.Run, но я предполагаю, что там есть delay t (или d?).

Вам необходимо скопировать параметры Execute в локальные переменные задачи внутрипринять заявление и только после этого позвонить Counter.Run;таким образом, и основная программа, и Countertask могут свободно работать.

task body CounterTask is
   Timeout : Counter.Timeout;
   Dur : Duration;
begin 
MyLoop:
   loop 
      select
         accept Execute(t:in Counter.Timeout;d:in Duration) do
            Timeout := T;
            Dur := D;
         end Execute;
         Counter.Run (Timeout, Dur);
      or
         delay 2.0;
         exit;
      end select;
   end loop MyLoop;
end CounterTask;
...