当从> 1个ISR访问变量但不在ISR外部共享变量时,是否需要volatile?


9

明确记录表明,当与ISR和主程序共享全局数据时,需要声明数据volatile以保证内存可见性(并且仅满足1字节数据;任何较大的数据都需要进行特殊安排以保证原子性) 。这里我们有很好的规则:

  • 仅在ISR外部使用的变量不应是volatile。
  • 仅在ISR内部使用的变量不应是可变的。
  • 在ISR内部和外部使用的变量应该是可变的。

但是volatile,当从1个以上的ISR访问变量但不与ISR共享外部变量时是否需要?例如,我有一个使用static变量维护内部状态的函数:

void func() {
    static volatile long counter; // volatile or not?
    // Do stuff with counter etc.
}

可以通过两种方式调用该函数:从引脚中断和从TimerOne库

  1. attachInterrupt(0, func, CHANGE);
  2. Timer1.attachInterrupt(func);

没有原子性问题,因为输入ISR时会自动禁用中断,但这volatile更多是编译器的问题:什么是缓存,什么不是。

当然比后悔好...

Answers:


9

volatile 仅通知编译器的代码生成器该变量可能被生成的代码以外的其他东西修改,因此不假定该变量的任何副本仍然准确。

必须在输入没有上下文的前提下编写/生成ISR代码,并在其(ISR)自己的操作周围保留CPU的上下文。因此,与非原子操作的不可分割性一样,在这种情况下,波动性取决于是否允许嵌套中断。如果保证非嵌套,则共享变量只能在自身执行期间被此ISR更改。如果您的ISR有一天可能在允许嵌套中断的环境中使用,则该约束将不再成立。

* 在这种情况下
我在这里假设一个软件维护的变量。如果我们谈论的是可以通过硬件事件进行更新的变量,例如计时器寄存器,那么所有的赌注都关闭了:无论如何,该变量都是易失的。


因此,只要我不更改Arduino的默认“中断不嵌套”行为,那么该变量就不必为volatile,因为除了生成的代码外,它不会被其他任何东西修改。只要中断不嵌套,编译器就可以“假定” ISR是线性执行的,并且可以执行。这就说得通了。谢谢!
Joonas Pulakka 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.