确定干扰的可能性

时间:2016-07-15 10:39:32

标签: c real-time interrupt multitasking rtos

在多任务环境中。如果任务具有表达式y = x + x;,则在两次读取x之间可能发生中断(任务切换)。

2 个答案:

答案 0 :(得分:1)

在大多数情况下,编译器生成的代码只会读取x一次,因为优化很简单。事实上,它甚至可能将操作转换为右移,相当于x << 1。但是你不能保证,如果x被声明为volatile,它必然会使两次读取在读取低阶和高阶词之间不会中断(反之亦然),在这种情况下,y的分配也是可以中断的。

另一个问题是,如果x不是原子数据类型(即无法在单个指令中读取),例如16位目标上的32位类型,那么即使它是一个单读,可能是可中断的。

在任何一种情况下,如果x本身(或第二种情况下的y)在上下文之间共享,通常只会出现问题(在这种情况下,它也应该声明为volatile所以两次读取是必要的),或者如果由于某种原因,分配的时间在某种程度上是关键的,并且需要完全确定(不太可能)。

如果x是共享的,因此是volatile但是是原子类型,此示例中的简单解决方案是编写表达式y = x << 1或{{ 1}}确保y = x * 2只读一次。其中x不是原子的 - 您可能需要锁定调度程序或禁用中断(即使用关键部分),或者更有选择地使用互斥锁保护访问权限。对于表达式不能简化为对共享变量的单个引用的更复杂的表达式,只需将变量分配给非共享的本地临时变量,即可确保只读取一次。原子性问题仍然存在。

答案 1 :(得分:-1)

这里是x86架构的特定答案,与传统的调度程序(https://en.wikipedia.org/wiki/Completely_Fair_Scheduler)一起使用。看看这个asm代码,由gcc为x86生成,优化设置为-OS0。

https://godbolt.org/g/AfKTkF

int main(void) {
  int y;
  int x = 5;
  y = x + x;
}

转向

main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $5, -4(%rbp)
        movl    -4(%rbp), %eax  #read x
        addl    %eax, %eax      #execute x + x
        movl    %eax, -8(%rbp)
        movl    $0, %eax
        popq    %rbp
        ret

正如你所看到的,x只被读取一次,因此暗示即使有任务切换,也不会有第二次读取。

修改 EOL在评论中指出x确实可以读取两次,修改上面的代码产生如下:

volatile x = 5;

强制编译器插入两个movl操作(而不是一个):

movl    -8(%rbp), %edx
movl    -8(%rbp), %eax

这不会让我的第一次猜错。编译器将优化变量的读访问(如果它是简单类型)并删除第二次读取。 volatile关键字强制编译器访问寄存器中的最新值。第一个代码不会强制读取 - 因此在线程切换和修改x时会产生其他结果。