在Ada95中,我们有两个相同类型的数组。如果我们像这样分配一个:
Array_A := Array_B;
这究竟是做什么的?
它会迭代Array_B并依次将每个元素分配给Array_A吗?或者它只是将Array_A的地址更改为Array_B的地址?
询问的原因是我们需要知道这个赋值是否是原子操作。
答案 0 :(得分:2)
Array_A的内容最终是Array_B元素的副本,即赋值遍历数组,分配每个元素。与C不同,Ada具有真正的数组对象。
因此,除非您以protected object之类的方式保护操作,否则赋值不是原子的。 (在受保护对象中包装数组赋值不会使其成为原子,它只是从应用程序其余部分的角度出现。)
答案 1 :(得分:2)
假设
type My_Array is array (1 .. 42) of Integer;
Array_A : My_Array;
Array_B : My_Array;
然后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);
来告诉编译器使访问值成为原子,或者如果可以的话就无法编译代码“T)。
答案 2 :(得分:1)
赋值语句复制数据。 Ada区分了包含数据的对象和仅对数据“引用”的对象;引用的对象具有access
类型的类型(例如Simon的示例中的My_Array_P
)。分配访问类型会导致引用指向同一个对象;但是,分配不是访问类型的对象总是会复制数据。
说数组赋值“在Array_B上迭代[s]并依次将每个元素[s]分配给Array_A”并不完全准确。如果数组元素类型是受控类型或具有受控子组件,那么Array_A := Array_B;
必须最终确定Array_A
的元素,之后它必须调整它们,但它按以下顺序发生:首先,{{1}的每个元素1}}最终确定(以任意顺序)。然后将数据从Array_A
复制到Array_B
(这可以一次完成一个元素,但在许多情况下,编译器可以将其优化为块复制)。然后调整Array_A
的每个元素(再次,以任意顺序)。因此Array_A
的语义不同于循环(我假设数组的上限和下限相同):
Array_A := Array_B
因为for I in Array_A'range loop
Array_A (I) := Array_B (I);
end loop;
和Finalize
调用将以不同的顺序完成。通常这不会对程序产生任何影响,如果Adjust
和Finalize
被正确写入(如果效果不同,程序设计可能有些奇怪)。但是,如果Adjust
释放内存并Finalize
分配新内存(例如在典型的Adjust
实施中),则进行Unbounded_String
和Finalize
调用以不同的顺序可能会对内存碎片产生影响。
答案 3 :(得分:1)
问题的答案是,如果您希望编译器对它们进行原子分配,则应声明对象“Atomic”。
如果您的目标CPU没有适合对象类型的原子指令,它会抱怨。在这种情况下,您(至少)有一个替代解决方案:
使用访问类型和复制引用当然是一种选择,但它实际上是一种完全不同的操作,因此您应该仔细考虑这是否真的是您想要的。
(如果有问题的数组很短,填充的布尔数组,你的编译器很可能能够使对象“Atomic”,否则我不会指望它。)