2017-01-06 326 views
1

我目前停留在創建兩個任務內部的過程添加數組傳遞給相應的過程。輸出參數undefined

我的通用包裝看起來是這樣的:

generic 
    type Item_Type is private; 
    with function "+"(Left: Item_Type; Right: Item_Type) return Item_Type; 
package Parallel_Algorithms is 

    type Array_Type is array(Natural range <>) of Item_Type; 
    type Array_Access_Type is access all Array_Type; 

    procedure Parallel_Sum(Input: Array_Access_Type; Result: out Item_Type); 

end Parallel_Algorithms; 

我實現了Parallel_Sum方法通過以下方式,意識到該實現是不完美的,也不是線程安全的。

procedure Parallel_Sum(Input: Array_Access_Type; Result: out Item_Type) is 

    Loop_Var: Integer:= 0; 

    task type T; 
    Task1, Task2 : T; 

    task body T is 
     begin 
      while Loop_Var < Input'Length loop 
       Result := Result + Input(Loop_Var); 
       Loop_Var := Loop_Var + 1; 
     end loop; 
    end T; 

begin 
    -- Result := Temp; 
end Parallel_Sum; 

如果我現在運行我的主程序Result輸出總是最終被類似1918988326.考慮到我的數組(1,2,3,4),其結果顯然是錯誤的內部元素。

我在另一篇文章中讀到,不改變out類型可能導致相應變量的未定義行爲。

什麼纔是真正的'真正的'Result

+0

你的任務體循環是完全錯誤的。您正在遍歷數組的長度,而不是遍歷其索引值的範圍。 –

+0

您可以將參數更改爲 類型Input_Type爲<>; 這將強制Input_Type爲整數類型。您將不需要傳入「+」功能。 –

+0

我明白你的意思,但我想過要開始這兩個任務,每個任務都將當前索引的值添加到結果中。通過這樣做,我可以在Loop_Var等於列表長度的地方獲得完整的結果,並且循環將終止以及任務? – hGen

回答

4

在仔細觀察問題後,我發現有幾個問題需要解決。任務必須累積自己的總數,然後這些總數必須合併。將總數添加到不受保護的Result變量將產生競態條件,這將導致未定義的結果。

以下是我對該問題的處理方法。

------------------------------------------------------------------ 
-- Parallel Addition of Array Elements -- 
------------------------------------------------------------------ 
generic 
    type Element_Type is range <>; 
package Parallel_Addition is 
    type Array_Type is array(Natural range <>) of Element_Type; 
    type Array_Access is access all Array_Type; 

    task type Adder is 
     Entry Set_Slice(Low, High : in Natural; 
         Item : in not null Array_Access); 
    end Adder; 

    protected Result is 
     procedure Accumulate(Item : in Element_Type); 
     function Report return Element_Type; 
    private 
     Sum : Integer := 0; 
    end Result; 

end Parallel_Addition; 
package body Parallel_Addition is 

    ----------- 
    -- Adder -- 
    ----------- 

    task body Adder is 
     My_Array  : Array_Access; 
     Id_Low, Id_High : Natural; 
     Sum    : Integer := 0; 
    begin 
     accept Set_Slice(Low, High : in Natural; 
         Item : in not null Array_Access) do 
     Id_Low := Low; 
     Id_High := High; 
     My_Array := Item; 
     end Set_Slice; 
     for I in Id_Low..Id_High loop 
     Sum := Sum + Integer(My_Array(I)); 
     end loop; 
     Result.Accumulate(Element_Type(Sum)); 
    end Adder; 

    ------------ 
    -- Result -- 
    ------------ 

    protected body Result is 

     ---------------- 
     -- Accumulate -- 
     ---------------- 

     procedure Accumulate (Item : in Element_Type) is 
     begin 
     Sum := Sum + Integer(Item); 
     end Accumulate; 

     ------------ 
     -- Report -- 
     ------------ 

     function Report return Element_Type is 
     begin 
     return Element_Type(Sum); 
     end Report; 

    end Result; 

end Parallel_Addition; 
------------------------------------------------------------------ 
-- Parallel_Addition Test -- 
------------------------------------------------------------------ 
with Ada.Text_IO; use Ada.Text_IO; 
with Parallel_Addition; 

procedure PA_Test is 
    package adders is new Parallel_Addition(Natural); 
    use adders; 
    Data : aliased Array_Type := (1,2,3,4,5,6,7,8,9,10); 
    T1, T2 : Adder; 
begin 
    T1.Set_Slice(Low => 0, High => 4, Item => Data'Access); 
    T2.Set_Slice(Low => 5, High => 9, Item => Data'Access); 
    loop 
     if T1'Terminated and then T2'Terminated then 
     exit; 
     end if; 
    end loop; 
    put_Line("The sum is " & Integer'Image(Result.Report)); 
end PA_Test;