在Ada95中,我們有兩個相同類型的數組。如果我們像這樣分配一個給另一個:Ada95數組賦值是改變指針還是賦值每個元素?
Array_A := Array_B;
這是幹什麼的?
它會迭代Array_B並將每個元素依次分配給Array_A嗎?或者只是將Array_A的地址更改爲Array_B的地址?
問的原因是我們需要知道這個任務是否是一個原子操作。
在Ada95中,我們有兩個相同類型的數組。如果我們像這樣分配一個給另一個:Ada95數組賦值是改變指針還是賦值每個元素?
Array_A := Array_B;
這是幹什麼的?
它會迭代Array_B並將每個元素依次分配給Array_A嗎?或者只是將Array_A的地址更改爲Array_B的地址?
問的原因是我們需要知道這個任務是否是一個原子操作。
賦值語句複製數據。 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;
因爲Finalize
和Adjust
呼叫將按照不同的順序來完成。通常這應該對程序沒有任何影響,如果Finalize
和Adjust
被正確寫入(如果效果不同,程序設計可能有些奇怪)。但是,如果Finalize
釋放內存並且Adjust
分配新內存(例如在典型的Unbounded_String
實現中),則以不同順序調用Finalize
和Adjust
可能會影響內存碎片。
Array_A的內容最終成爲Array_B元素的副本,即分配遍歷數組,分配每個元素。 Ada擁有真正的數組對象,與C不同。因此,除非像protected object那樣保護操作,否則賦值不是原子的。 (在一個受保護對象包裝紙數組指派不會使它原子,它只是顯示從應用程序的其餘部分的角度的方式。)
假設
然後Array_A
和Array_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);
告訴編譯器,使訪問值原子或失敗編譯代碼,如果它不能)。
您的問題的答案是您應該聲明對象「Atomic」,如果您希望編譯器將它們賦值爲atomic。
如果你的目標CPU沒有合適的對象類型的原子指令,它會發出抱怨。在這種情況下,您至少有一種替代解決方案:
使用訪問類型和複製引用當然是一個選項,但它實際上是一個完全不同的操作,因此您應該仔細考慮是否真的是您想要的。
(如果所討論的數組是短布爾數組,則編譯器可能會使對象成爲「原子」,否則我不會期望它。)