仅在 ISR 中读取的变量的易失性?

volatile for variable that is only read in ISR?

对于在主循环中读写但在 ISR 中只读的变量是否需要 volatile

编辑:在写入 main 时,ISR 被禁用。因此,变量被有效地原子使用。

编辑:(非常相关):

Is volatile needed for a variable that is read&write in main loop, but read-only in ISR?

volatile 不是这里的问题,只要确保 main 循环的写入不会被分解即可。

在没有 ISR 调用保护的情况下 main() 中的任何更改都可能导致问题,volatile 或没有。声明它 volatile 不会保存该问题的代码。

volatile some_type obj;

void ISR() {
  foo(obj);
}

int main() {
  for (;;) {
    // volatile useful here to prevent the assignment from being optimized away.
    some_type tmp = bar();

    // protect from potential interruption need here.

    // Without protection, ISR(), 
    // doesn't know it is working with a completely written `obj`
    obj = tmp;

    // release from potential interruption
}

volatile 在两个方向上都有用,因为 main() 知道 ISR() 可能已经改变 obj 并且 main() 不优化离开分配。

但由于ISR()不会改变obj,所以不需要volatile

声明 obj atomic 可能会有所帮助 - 但这是另一个问题。

volatile 是一种糟糕的同步访问方式。这是一个优化障碍,但仅此而已。

  • 它不是原子的;例如当您的 some_type 在没有本机 64 位数据类型的平台上是 uint64_t 时,可能有一部分是只读的。例如

    main()                  irq()
    
    /* initialization */ 
    var[0..31]  = 4
    var[32..63] = 8
    
    /* modificatoin */ 
    var[32..63] = 23
                          /* read */
                          a_hi = var[32..64] = 32
                          a_lo = var[0..31]  = 4
    var[0..31] = 42
    
  • 根据体系结构,可能需要内存屏障操作。例如。当 mainirq 在具有专用缓存的不同内核上运行时,irq 将永远不会看到更新的值

第一个问题需要锁定,但锁定操作通常意味着优化障碍,因此 volatile 是多余的。

同上第二个问题,其中内存屏障也充当优化屏障。

volatile 对于实现对处理器内存的访问很有用(这可能会在两次读取之间发生变化或在写入时产生副作用)。但通常,它是不需要的,而且太贵了。