是否有必要将共享数组数据包装在受保护的类型中?

Is it necessary to wrap shared array data in a protected type?

我知道这通常是不好的做法(ARM 可能会说这是未定义的行为),但我正在尝试编写一个包含许多浮点数的快速文本解析器,并且包装起来会非常昂贵将加载的文本转换为受保护的类型,因为数据是逐个字符检查的,并且可能有多达一百万个浮点数或在堆栈上传递一个切片。

是否可以在 Ada (GNAT) 中 "safely" 划分一个未受保护的数组以供多个任务使用,因为该数组从不写入且仅读取?

如:

 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);
 ...

是的。这是安全的,因为没有与读取数据相关的竞争条件,也没有暂时重叠的写入操作。 例如,下面的代码使用这种技术对整数数组执行并行加法。

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;