2013-10-04 83 views
0

在Ada95中,我們有兩個相同類型的數組。如果我們像這樣分配一個給另一個:Ada95數組賦值是改變指針還是賦值每個元素?

Array_A := Array_B; 

這是幹什麼的?

它會迭代Array_B並將每個元素依次分配給Array_A嗎?或者只是將Array_A的地址更改爲Array_B的地址?

問的原因是我們需要知道這個任務是否是一個原子操作。

回答

1

賦值語句複製數據。 Ada對持有數據的對象和僅對數據「引用」的對象進行區分;作爲引用的對象的類型爲access類型(例如Simon的示例中的My_Array_P)。分配訪問類型會導致引用指向同一個對象;但分配不是訪問類型的對象始終會複製數據。

說數組賦值「通過Array_B迭代[s]並將每個元素依次賦值給Array_A並不完全準確」。如果數組元素類型是受控類型或具有受控子組件,則Array_A := Array_B;必須完成Array_A的元素,稍後它必須對其進行調整,但它按以下順序進行:首先,Array_A的每個元素都已完成(以任意順序)。然後將數據從Array_B複製到Array_A(這可以一次完成一個元素,但在很多情況下,編譯器可以將其優化爲塊副本)。然後調整Array_A的每個元素(再次按任意順序)。因而語義是從一個循環(我假設陣列的上界和下界是相同的)不同:

for I in Array_A'range loop 
    Array_A (I) := Array_B (I); 
end loop; 

因爲FinalizeAdjust呼叫將按照不同的順序來完成。通常這應該對程序沒有任何影響,如果FinalizeAdjust被正確寫入(如果效果不同,程序設計可能有些奇怪)。但是,如果Finalize釋放內存並且Adjust分配新內存(例如在典型的Unbounded_String實現中),則以不同順序調用FinalizeAdjust可能會影響內存碎片。

2

Array_A的內容最終成爲Array_B元素的副本,即分配遍歷數組,分配每個元素。 Ada擁有真正的數組對象,與C不同。因此,除非像protected object那樣保護​​操作,否則賦值不是原子的。 (在一個受保護對象包裝紙數組指派不會使它原子,它只是顯示從應用程序的其餘部分的角度的方式。)

2

假設

​​

然後Array_AArray_B是不同的領域的內存,並且在分配之後Array_A的字節包含Array_B的字節的副本。是否通過遍歷元素或某個等效的memcpy(3)來完成傳輸是由編譯器編寫者決定的(pragma Atomic_Components影響到這一點)。

如果在另一方面,你有

type My_Array is array (1 .. 42) of Integer; 
type My_Array_P is access My_Array; 
Array_A : My_Array_P; 
Array_B : My_Array_P; 

然後分配將複製的指針,也可以是原子的(你可以添加pragma Atomic (My_Array_P);pragma Atomic (Array_A);告訴編譯器,使訪問值原子或失敗編譯代碼,如果它不能)。

1

您的問題的答案是您應該聲明對象「Atomic」,如果您希望編譯器將它們賦值爲atomic。

如果你的目標CPU沒有合適的對象類型的原子指令,它會發出抱怨。在這種情況下,您至少有一種替代解決方案:

  1. 將數組封裝在受保護對象中以確保對它們的操作是原子操作。

使用訪問類型和複製引用當然是一個選項,但它實際上是一個完全不同的操作,因此您應該仔細考慮是否真的是您想要的。

(如果所討論的數組是短布爾數組,則編譯器可能會使對象成爲「原子」,否則我不會期望它。)