Нужно ли оборачивать данные общего массива в защищенный тип? - PullRequest
0 голосов
/ 11 октября 2018

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

Возможно ли в Ada (GNAT) "безопасно""разделить незащищенный массив для потребления несколькими задачами, учитывая, что массив никогда не записывается и только читается?

Как в:

 Text : array (1..1_000_000) of Character := ...
 begin
   Task_1.Initialize (Start_Index => 1, End_Index => 10_000);
   Task_2.Initialize (Start_Index => 10_001, End_Index => 20_000);
 ...

1 Ответ

0 голосов
/ 11 октября 2018

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

package Parallel_Addition is
   type Data_Array is array(Integer range <>) of Integer;
   type Data_Access is access all Data_Array;
   function Sum(Item : in not null Data_Access) return Integer;
end Parallel_Addition;

package body Parallel_Addition is

   ---------
   -- Sum --
   ---------

   function Sum (Item : in not null Data_Access) return Integer is
      task type Adder is
         entry Set (Min : Integer; Max : Integer);
         entry Report (Value : out Integer);
      end Adder;

      task body Adder is
         Total : Integer := 0;
         First : Integer;
         Last  : Integer;
      begin
         accept Set (Min : Integer; Max : Integer) do
            First := Min;
            Last  := Max;
         end Set;
         for I in First .. Last loop
            Total := Total + Item (I);
         end loop;
         accept Report (Value : out Integer) do
            Value := Total;
         end Report;
      end Adder;
      A1  : Adder;
      A2  : Adder;
      R1  : Integer;
      R2  : Integer;
      Mid : constant Integer := (Item'Length / 2) + Item'First;
   begin
      A1.Set (Min => Item'First, Max => Mid);
      A2.Set (Min => Mid + 1, Max => Item'Last);
      A1.Report (R1);
      A2.Report (R2);
      return R1 + R2;
   end Sum;

end Parallel_Addition;

with Parallel_Addition; use Parallel_Addition;
with Ada.Text_IO;       use Ada.Text_IO;
with Ada.Calendar;      use Ada.Calendar;

procedure Parallel_Addition_Test is
   The_Data : Data_Access := new Data_Array (1 .. Integer'Last / 5);
   Start    : Time;
   Stop     : Time;
   The_Sum  : Integer;

begin
   The_Data.all := (others => 1);
   Start        := Clock;
   The_Sum      := Sum (The_Data);
   Stop         := Clock;
   Put_Line ("The sum is: " & Integer'Image (The_Sum));
   Put_Line
     ("Addition elapsed time is " &
      Duration'Image (Stop - Start) &
        " seconds.");
   Put_Line
     ("Time per addition operation is " &
        Float'Image(Float(Stop - Start) / Float(The_Data'Length)) &
        " seconds.");
end Parallel_Addition_Test;
...