Как много раз вызвать задачу в Аде - PullRequest
2 голосов
/ 03 июня 2019

Я пытаюсь вызвать задачу 100 раз, но она не работает, кажется, мне нужно создать 100 записей для этого.Не могли бы вы дать несколько советов?

Я сейчас учусь использовать задание Ada: -)

with Ada.Text_IO ; use Ada.Text_IO;
procedure Main is

   task type test1 is
      entry start;
   end test1;

   task body test1 is
   begin
      accept start;
      Put_Line("Haha");
   end test1;

   t1 : test1;
N : Integer := 10;
begin
   while N /= 0 loop
     t1.start;
     N := N - 1;
   end loop;
end Main;

E: \ Ada Code \ Simple \ obj \ main.exe Хаха

повышен TASKING_ERROR [2019-06-03 17:55:17] процесс завершен со статусом 1, истекшее время: 01.00s

Ответы [ 2 ]

3 голосов
/ 03 июня 2019

Ваша проблема в том, что задача будет выполнена до завершения после принятия первого рандеву. Этого можно избежать, добавив в тело задачи цикл:

task body test1 is
begin
   loop
      accept start;
      Put_Line("Haha");
   end loop;
end test1;

(на самом деле большинство задач будет иметь такой цикл)

Задача теперь имеет бесконечный цикл, поэтому следующий шаг - убедиться, что ваша задача завершается, когда ваша основная программа завершена. В этом случае вы можете сделать это с помощью селективного подтверждения :

task body test1 is
begin
   loop
      select
         accept start;
      or
         terminate;
      end select;

      Put_Line("Haha");
   end loop;
end test1;
2 голосов
/ 07 июня 2019

Как правило, более эффективно вызывать запись задачи, передавая любые необходимые данные в задачу или из нее, чем запускать другую задачу. Нетривиальные издержки, связанные с запуском и завершением задачи. Альтернативой вызову записей задач для задач является реализация шаблона производитель-потребитель с использованием защищенных объектов.

Следующий пример производитель-потребитель создает трех производителей и одного потребителя. Каждый из производителей записывает 500 000 сообщений в общую очередь. Потребитель потребляет все сообщения, произведенные производителями.

------------------------------------------------------------------
-- Producer / Consumer example using 3 producers and 1 consumer --
-- Matches the number of tasks to a 4-core processor            --
------------------------------------------------------------------
with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Unbounded_Synchronized_Queues;
with Ada.Text_IO; use Ada.Text_IO;
With Ada.Calendar; use Ada.Calendar;
use Ada.Containers;

procedure PC_v3 is
   package Integer_Interface is new
     Synchronized_Queue_Interfaces(Element_Type => Integer);
   package Unbounded_Integer_Queues is new
     Unbounded_Synchronized_Queues(Queue_Interfaces => Integer_Interface);

   My_Queue      : Unbounded_Integer_Queues.Queue;
   Num_Producers : Constant := 3;
   Max_Produced  : constant := 500_000;
   Empty_Queue   : constant Count_Type := 0;
   Start_Time    : Time := Clock;

   -- The Counter protected object below is used to count the number of
   -- completed producers. This allows the consumer to know when all the
   -- data has been processed.
   ---------------------------------------------------------------------
   protected Counter is
      Procedure Task_Done;
      function All_Done return boolean;
   private
      Count : Natural := 0;
   end Counter;

   protected body Counter is
      procedure Task_Done is
      begin
         Count := Count + 1;
      end Task_Done;

      function All_Done return boolean is
      begin
         return Count = Num_Producers;
      end All_Done;
   end Counter;

   -- Define the producer task type.
   -- Producer is being defined as a task type to allow multiple instances
   -- of the producer to be easily created.
   ------------------------------------------------------------------------
   task type Producer;

   Task body Producer is
      Value : Positive := 1;
      Finis_Time : Time;
   begin
      loop
         My_Queue.Enqueue(Value);
         Value := Value + 1;
         if Value > Max_Produced then
            Counter.Task_Done;
            Finis_Time := Clock;
            Put_Line("Producer completed in" &
                       Duration'Image(Finis_Time - Start_Time) &
                       " seconds");
            exit;  -- exit the loop within the Producer task
         end if;
      end loop;
   end Producer;

   Read_Value : Integer;
   Done_Time  : Time;

   -- Create an array of producers. There are Num_Producers in this
   -- array. The Producer tasks start executing as soon as they are
   -- instantiated in the array.
   ----------------------------------------------------------------
   The_Producers : array(1..Num_Producers) of Producer;

begin
   -- Process the values in My_Queue until all producers are completed
   -- and the queue is empty.
   -- The program main task is being used as the consumer task.
   loop
      My_Queue.Dequeue(Read_Value);
      exit when Counter.All_Done and then My_Queue.Current_Use = Empty_Queue;
   end loop;
   -- Record the time stamp when all queue processing is done
   Done_Time := Clock;

   -- print out the execution statistics
   Put_Line("Queue element peak use:" & Count_Type'Image(My_Queue.Peak_Use));
   Put_Line("Elapsed time (seconds):" & Duration'Image(Done_Time - Start_Time));
end PC_V3;

Как видите, потребитель продолжает работать до тех пор, пока не будут использованы все данные, не зная, сколько производителей работает или сколько сообщений генерируется. Это гораздо эффективнее, чем когда каждый производитель звонит потребителю для каждого созданного сообщения.

...