同步ISR访问是否需要易失性?

在下面的代码片段中,中断例程使用许多数组中的一个来执行它。 使用的数组是同步选择的, 而不是异步的 (在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阻止编译器对其进行优化,从而强制编译器

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

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

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

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

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

如果不使用volatile,则在中断中使用代码之前,代码仍可能在寄存器中具有新值。

 int * volatile foo; 

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


 int volatile * volatile foo 

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

更新

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

从标准n4296

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

来自cppreference cv对象

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

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

来自: C ++标准:n4296

我们有 :-

在与要评估的下一个全表达式相关联的每个值计算和副作用之前,对与全表达相关联的每个值计算和副作用进行排序。

据我所知,对于任何具有副作用的操作,都存在一种先happens-before关系。

严格根据抽象机器的规则来评估对易失性对象的访问

据我所知,有规则(可能不透明)。

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

从中我了解到访问volatile(以及其他一些东西)会产生副作用,从而阻止编译器在易失性访问附近重新排序语句。