跳转到内容

Ada 编程/编译指示/Atomic

来自 Wikibooks,开放的书籍,开放的世界

Ada. Time-tested, safe and secure.
Ada。经久不衰,安全可靠。
pragma Atomic (local_name);

Atomic 是一个 表示编译指示,它可以与类型和变量一起使用,以指定生成的代码必须以原子方式从内存中读取和写入类型或变量,即作为单个/不可中断的操作。它隐含了编译指示 Volatile,不同之处在于编译指示 Atomic 更强大:如果无法以原子方式更新变量,则编译必须失败。

这通常用于与硬件寄存器交互的上下文中,这些寄存器必须以原子方式写入,并且编译器不得重新排序或抑制任何冗余读写操作。在某些情况下,它也可以用于任务,但对于 Ada 任务的通信,使用保护类型 或其他同步原语更安全。

Device_Status : Status_Register;
pragma Atomic (Device_Status);
for Device_Status'Address use [[Ada Programming/Libraries/|]].System.Storage_Elements.To_Address (16#8010_FF74#);

错误用法

[编辑 | 编辑源代码]

几乎总是错误地将 atomicvolatile 变量用于 任务.[1] 当一个对象是原子的时候,它只是意味着它将被原子地读入或写入内存。编译器不会为访问该对象生成原子指令或内存屏障,它只会

  • 检查体系结构是否保证原子内存加载和存储,
  • 禁止某些编译器优化,例如重新排序或抑制对该对象的冗余访问。

例如,以下代码,其中A是一个原子对象,可能会被误解

A := A + 1;  -- Not an atomic increment!

编译器不会(并且标准不允许)生成原子增量指令来直接增量和更新内存中的变量A.[2] 这是编译器生成的代码

  A := A + 1;
804969f:	a1 04 95 05 08       	mov    0x8059504,%eax
80496a4:	40                   	inc    %eax
80496a5:	a3 04 95 05 08       	mov    %eax,0x8059504

如您所见,不会生成原子增量指令或 test-and-set 操作码。与其他编程语言一样,如果程序中需要这些特定指令,则必须使用机器代码插入显式地写入它们。[3]

上面的代码片段等效于以下代码(两个代码序列生成完全相同的目标代码),其中T是一个(非原子)临时变量

T := A;      -- A is copied atomically to local variable T
T := T + 1;  -- local variable T is incremented
A := T;      -- A is stored atomically

因此,从多个任务同时修改原子变量是不正确的。例如,两个任务并行递增计数器。即使在单处理器中,也应使用其他 Ada 任务功能(例如保护对象)来代替。在多处理器中,根据 内存一致性模型,使用各种原子或易失变量进行任务通信可能会产生意想不到的结果。[2][4] 因此,在将原子对象用于任务数据共享或同步时,尤其是在多处理器中,应格外小心。

  1. Arch Robison (2007-11-30). "Volatile: Almost Useless for Multi-Threaded Programming". Intel Software Network. Retrieved 2008-05-30. There is a widespread notion that the keyword volatile is good for multi-threaded programming (...) volatile is almost useless for multi-threaded programming.
  2. a b Ian Lance Taylor (2008-03-05). "Volatile". Retrieved 2008-05-28. Using [the C/C++ qualifier] volatile does not mean that the variable is accessed atomically; no locks are used. Using volatile does not mean that other cores in a multi-core system will see the memory accesses; no cache flushes are used. (...) Using volatile does not imply any sort of memory barrier; the processor can and will rearrange volatile memory accesses. (...) You should not use more than one such variable to communicate between any pair of threads, as there is no guarantee that the different threads will see the accesses in the same order.
  3. Laurent Guerby (1995). "C.5 Shared Variable Control". Ada 95 Rationale. Intermetrics. A need to access specific machine instructions arises sometimes (...). Examples include instructions that perform compound operations atomically on shared memory, such as test-and-set and compare-and-swap (...) {{cite book}}: |access-date= requires |url= (help); External link in |chapter= (help); Unknown parameter |month= ignored (help)
  4. Sarita V. Adve, Kourosh Gharachorloo (1996). "Shared Memory Consistency Models: A Tutorial" (PDF). IEEE Computer. 29 (12): 66–76. Retrieved 2008-05-28. {{cite journal}}: Unknown parameter |month= ignored (help)

可移植性

[编辑 | 编辑源代码]

编译器

[编辑 | 编辑源代码]

Atomic 是 Ada 95 以来标准的编译指示,定义在系统编程附录(附录 C)中。这是一个专门需求的附录,因此该编译指示在那些没有实现该附录的编译器中不可用。

Ada 版本

[编辑 | 编辑源代码]
  • 在 Ada 95 和 Ada 2005 中可用。
  • 在 Ada 83 中,pragma Shared 产生与 pragma Atomic 类似的效果(但它自 Ada 95 以来已过时)。[1]

Atomic 是不同平台之间可移植性的辅助工具。例如,在 64 位架构与 32 位架构之间移植时,编译器将借助此 pragma 检测可移植性问题。

pragma Atomic 的效果可以在 C 中使用以下类型实现volatile sig_atomic_t,在 signal.h 中定义(在 C++ 中称为volatile std::sig_atomic_t)。值得注意的是,可以可移植地存储在此类型中的唯一值是 0–127,[2] 而 Ada pragma 并没有施加任何特定的限制(除了原子对象的类型)。

但是,这种 C 类型很少为程序员所知。因此,C 中的volatile限定符被广泛用于易变数据和原子数据,即使需要原子访问。因此,在与现有 C 代码进行接口时,程序员必须首先阅读代码以了解数据是否需要原子加载和存储。如果需要,应在 Ada 端使用 pragma Atomic 或 Atomic_Components 标记数据。否则,应改为添加 pragma VolatileVolatile_Components

C++11C11 包含了原子操作和类型,[3] 但与 Ada 中的语义不同,也不兼容。

另请参阅

[编辑 | 编辑源代码]

维基教科书

[编辑 | 编辑源代码]

Ada 参考手册

[编辑 | 编辑源代码]

Ada 95 理据

[编辑 | 编辑源代码]

Ada 95 质量和风格指南

[编辑 | 编辑源代码]
  1. Robert Dewar (1996-02-17)。“pragma Shared (was Ada is almost ....)”。comp.lang.ada(网络链接)。于 2008-05-28 检索。 “pragma Atomic 与 pragma Volatile 完全不同。 Ada 中的 pragma Atomic 本质上等同于 Ada 83 中的 pragma Shared。Ada 中的 pragma Volatile 本质上等同于 C 中的 volatile,并且是 Ada 83 中没有的功能。”
  2. Justin Pincar (2008-11-19)。“DCL34-C. 对无法缓存的数据使用 volatile”CERT C 安全编码标准计算机紧急响应小组. 于 2009-01-10 检索从 0 到 127 的整数值可以安全地存储到类型为 sig_atomic_t 的变量中。
  3. Herb Sutter (2009-01-08)。“volatile vs. volatile”Dr. Dobb's. 于 2009-01-10 检索ISO C++ 在 2007 年将它们添加到 C++0x 草案标准中,使用模板名称 atomic<T>(例如,atomic)。它们从 2008 年开始在 Boost 项目 和其他实现中变得可用。ISO C++ 原子库还提供了一种与 C 兼容的方式来拼写这些类型及其操作(例如,atomic_int),这些类型似乎很可能在将来被 ISO C 采用。 {{cite journal}}: 外部链接在 |quote= (帮助)
华夏公益教科书