同步ISR访问是否需要使用volatile? [英] Is volatile required for synchronous ISR access?

查看:108
本文介绍了同步ISR访问是否需要使用volatile?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码片段中,中断例程使用许多数组之一来执行它。所使用的数组是同步选择的,不是不是异步(在执行ISR时,它永远不会改变)。在单核微控制器上(如果体系结构很重要,此问题假定为STM32L496)在 foo volatile 修饰符c $ c>?

In the following code snippet, an interrupt routine uses one of many arrays for its execution. The array used is selected synchronously, not asynchronously (it will never change while the ISR is executing). On a single core microcontroller (this question assumes an STM32L496 if the architecture is important), is the volatile specifier required in the declaration of foo?

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 是正确的。

My assumption is that the volatile specifier is not required because any caching of the value of foo will be correct.

编辑:

为了澄清,最后的答案是需要 volatile 或其他同步方式,否则可以省略或重新排序对 foo 的写入。缓存不是唯一的问题。

To clarify, the final answer is that volatile or some other synchronisation is required because otherwise writes to foo can be omitted or reordered. Caching is not the only concern.

推荐答案

volatile 停止编译器优化它,迫使编译器

volatile stops the compiler optimizing it, forcing the compiler


  • 要始终读取内存,而不是寄存器中的缓存值

  • 在易失性读/写之前或之后不移动事物

在复杂的CPU(例如x86)上,

On a complex CPU (e.g. x86), it is possible for the CPU to re-order operations before, or after a volatile access.

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

It is typically for memory-mapped-io, where regions of memory, are actually devices, and can change (even on a single core CPU), without visible cause.

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

The mechanism for C++11 is to use std::atomic to change a value which may occur on different threads of execution.

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

With a single core, the code will safely modify the value, and store it. If you use volatile, then it will be written to the memory point, before the interrupts are enabled.

如果您不使用volatile,则代码可能仍然包含在中断之前使用寄存器中的新值。

If you don't use volatile, then the code may still have the new value in a register before it is used in the interrupt.

int * volatile foo;

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

Describes that foo can change, but the values it points to, are stable.

int volatile * volatile foo

描述foo可以更改,它指向的内容也可以更改。我认为您想要 int * volatile foo;

Describes foo can change, and the things it points to can also change. I think you want int * volatile foo;

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

For those who doubt that volatile is a compiler barrier.

来自标准n4296


访问由易失性glvalue(3.10)指定的对象,修改对象,调用库I / O
函数或调用函数这些操作中的任何一个都是副作用,它们是执行环境的
状态中的更改。表达式(或子表达式)的评估通常包括
的值计算(包括确定对象的身份以进行glvalue评估以及获取先前分配给对象的
a值以进行prvalue评估)和初始化。副作用。当对库I / O函数的调用
返回或评估了对易失对象的访问时,即使该调用隐含了某些外部操作(例如I / O本身)或不稳定的
访问可能尚未完成。

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对象


易失性对象-类型为volatile限定的对象,或易失性对象的子对象,或const-volatile对象的可变子对象。出于优化目的(即在单个执行线程中,通过volatile限定类型的glvalue表达式进行的每次访问(读取或写入操作,成员函数调用等)都被视为可见的副作用)无法优化访问,也不会因其他易见的副作用(在volatile访问之前或之后)而被优化或重新排序,这使得volatile对象适合与信号处理程序进行通信,但不适合与其他执行线程进行通信,请参见std :: memory_order )。任何尝试通过非易失性glvalue引用易失性对象(例如,通过对非易失性类型的引用或指针)都会导致未定义的行为。

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原子不可用,这似乎是一种合适的机制。

These seem to concur, that there is a compiler barrier, but some of the side effects of interacting with the volatile object may not have completed. For the single core processor, it appears to be a suitable mechanism if C++11 atomics are not available.

来自: C ++标准: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.

据此,我有一个具有副作用的任何操作的发生前的关系。

From this I understand, there is a happens-before relationship for any operation with a side-effect.


评估对易失对象的访问严格按照抽象机的规则

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

据此我知道,存在规则(可能是不透明的)。

From this I understand, that there are rules (which maybe opaque).


访问由易失性glva指定的对象lue(3.10),修改对象,调用库I / O
函数或调用执行任何这些操作的函数都是副作用,它们是执行环境中
状态的变化。表达式(或子表达式)的评估通常包括
的值计算(包括确定对象的身份以进行glvalue评估以及获取先前分配给对象的
a值以进行prvalue评估)和初始化。副作用。当对库I / O函数的调用
返回或评估了对易失对象的访问时,即使该调用隐含了某些外部操作(例如I / O本身)或通过易失性
访问可能尚未完成。

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的访问(和其他一些东西),会产生副作用,使编译器无法在易失性访问附近对语句进行重新排序。

From this I understand that access to volatile (and a few other things), create a side effect, which stops the compiler from re-ordering statements near a volatile access.

这篇关于同步ISR访问是否需要使用volatile?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆