同步 ISR 访问是否需要 volatile?

Is volatile required for synchronous ISR access?

在以下代码片段中,中断例程使用多个数组中的一个来执行。使用的数组是同步选择的,不是异步选择的(它在 ISR 执行时永远不会改变)。在单核微控制器上(如果架构很重要,这个问题假定是 STM32L496),foo 的声明中是否需要 volatile 说明符?

int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int * foo; //int * volatile foo? int volatile * volatile foo?

main(){
    disable_interrupt();
    foo = a;
    enable_interrupt();
    ...
    disable_interrupt();
    foo = b;
    enable_interrupt();
}

void interrupt(){
    //Use foo
}

我的假设是 volatile 说明符 不需要 因为 foo 值的任何缓存都是正确的。

编辑:

澄清一下,最终答案是 volatile 或其他一些同步是必需的,因为否则写入 foo 可以省略或重新排序。缓存不是唯一的问题。

volatile 停止编译器优化它,强制编译器

  • 始终读取内存,而不是寄存器中的缓存值
  • 在 volatile 之前或之后不要移动东西 read/write

在复杂的 CPU(例如 x86)上,CPU 可以在可变访问之前或之后重新排序操作。

它通常用于内存映射 io,其中内存区域实际上是设备,并且可以更改(即使在单个内核 CPU 上),没有明显的原因。

C++11的机制是使用std::atomic改变一个可能出现在不同执行线程上的值。

对于单核,代码将安全地修改值并存储它。如果您使用 volatile,那么它将在启用中断之前写入内存点。

如果您不使用 volatile,那么在中断中使用新值之前,代码可能仍将新值保存在寄存器中。

int * volatile foo;

描述 foo 可以改变,但它指向的值是稳定的。


int volatile * volatile foo

描述foo是可以改变的,它指向的东西也是可以改变的。我想你想要 int * volatile foo;

更新

对于那些怀疑 volatile 是编译器障碍的人。

来自标准 n4296

Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function returns or an access to a volatile object is evaluated the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.

来自 cppreference cv object

volatile object - an object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order). Any attempt to refer to a volatile object through a non-volatile glvalue (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.

这些似乎一致,存在编译器障碍,但与 volatile 对象交互的一些副作用可能尚未完成。对于单核处理器,如果 C++11 原子不可用,它似乎是一种合适的机制。

发件人:C++ standard : n4296

我们有:-

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

据我了解,任何具有副作用的操作都存在 happens-before 关系。

Access to volatile objects are evaluated strictly according to the rules of the abstract machine

由此我了解到,有规则(可能不透明)。

Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function returns or an access to a volatile object is evaluated the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.

据我所知,访问 volatile(以及其他一些东西)会产生副作用,这会阻止编译器对 volatile 访问附近的语句重新排序。