跳转到内容

Ada 编程/编译指示/Volatile

来自维基教科书,开放的书籍,用于开放的世界

Ada. Time-tested, safe and secure.
Ada. 经久耐用,安全可靠。
pragma Volatile (local_name);

Volatile 是一种 表示编译指示,可用于类型和变量,以指定所讨论的变量的值可能会突然发生变化。例如,这可能是由于设备写入共享缓冲区造成的。

当使用此编译指示时,编译器必须抑制任何会干扰对易失性变量的正确读取的优化。例如,对同一变量的两次连续读取不能优化为仅一次读取,也不能重新排序。

与编译指示 AtomicAtomic_ComponentsVolatile_Components 进行比较。

type Video_Buffer is array (Natural range <>) of RGB_Value;
pragma Volatile (Video_Buffer);

错误用法

[编辑 | 编辑源代码]

对于 任务 来说,使用 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

可以看出,不会生成原子增量指令或测试和设置操作码。与其他编程语言一样,如果程序中需要这些特定指令,则必须使用机器码插入显式编写。[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 软件网络. 检索于 2008-05-30. 有一种普遍的观点认为,关键字 volatile 对多线程编程很有用 (...) volatile 对多线程编程几乎没有用处。
  2. a b Ian Lance Taylor (2008-03-05). "Volatile". 检索于 2008-05-28. 使用 [C/C++ 限定符] volatile 并不意味着变量是以原子方式访问的;不使用锁。使用 volatile 并不意味着多核系统中的其他内核将看到内存访问;不使用缓存刷新。(...) 使用 volatile 并不意味着任何形式的内存屏障;处理器可以并且将会重新排列 volatile 内存访问。(...) 您不应该使用多个这样的变量在任何一对线程之间进行通信,因为无法保证不同的线程会以相同的顺序看到访问。
  3. Laurent Guerby (1995). "C.5 Shared Variable Control". Ada 95 论证. Intermetrics. 有时需要访问特定的机器指令 (...). 例如,在共享内存上执行复合操作的原子指令,例如测试和设置和比较和交换 (...) {{cite book}}: |access-date= requires |url= (帮助); External link in |chapter= (帮助); Unknown parameter |month= ignored (帮助)
  4. Sarita V. Adve, Kourosh Gharachorloo (1996). "Shared Memory Consistency Models: A Tutorial" (PDF). IEEE Computer. 29 (12): 66–76. 检索于 2008-05-28. {{cite journal}}: Unknown parameter |month= ignored (帮助)

可移植性

[编辑 | 编辑源代码]

Ada 版本

[编辑 | 编辑源代码]
  • 此编译指示在 Ada 95 和 Ada 2005 中可用(附件 C,一个专门需求附件)。
  • 在 Ada 83 中,没有一个完全等同于 Volatile 的标准编译指示。但是,编译指示 Shared 与 Atomic 相似(尽管它自 Ada 95 以来已过时),[1] 并且一些编译器为此目的添加了一个实现定义的编译指示。[2]

编译器

[编辑 | 编辑源代码]

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

此编译指示可移植到不同的架构和操作系统。

在 C/C++ 中,volatile限定符等效于此编译指示。但是,此 C 限定符用于易变和原子数据,即使需要原子访问也是如此。因此,在与现有 C 代码进行接口时,程序员必须阅读代码以了解数据是否需要原子加载和存储。如果需要,数据应在 Ada 侧使用编译指示 AtomicAtomic_Components 标记,否则使用编译指示 Volatile 或 Volatile_Components

编码规则

[编辑 | 编辑源代码]

没有地址子句的易变对象

[编辑 | 编辑源代码]

在许多情况下,当易变对象用于与硬件设备进行接口时,它也应该有一个地址子句。

  • gnatcheck
 +R Volatile_Objects_Without_Address_Clauses
  • AdaControl
 check object_declarations (volatile_no_address);

另请参阅

[编辑 | 编辑源代码]

维基教科书

[编辑 | 编辑源代码]

Ada 参考手册

[编辑 | 编辑源代码]

Ada 95 理性

[编辑 | 编辑源代码]

Ada 95 质量和风格指南

[编辑 | 编辑源代码]
  1. 罗伯特·德沃(1996 年 2 月 17 日)。"编译指示 Shared(是 Ada 几乎是……)". comp.lang.ada. (网页链接). 检索于 2008 年 5 月 28 日。 "编译指示 Atomic 与编译指示 Volatile 截然不同。 Ada 中的编译指示 Atomic 本质上与 Ada 83 中的编译指示 Shared 相同。 Ada 中的编译指示 Volatile 本质上与 C 中的 volatile 相同,它是在 Ada 83 中不可用的功能。"
  2. "实现定义的编译指示". GNAT Pro 参考手册. 检索于 2008 年 6 月 2 日. [编译指示 Volatile] 在一些 Ada 83 编译器中提供,包括 DEC Ada 83。 Ada 95 / Ada 2005 中编译指示 Volatile 的实现与 DEC Ada 83 中的实现向上兼容。 {{cite book}}: 未知参数 |chapterurl= 被忽略 (|chapter-url= 建议) (帮助)
华夏公益教科书