在C语言中,在主程序和ISR之间共享易失性变量是否安全?

在C语言中,在主程序和ISR之间共享易失性变量是否安全?,c,embedded,volatile,C,Embedded,Volatile,在C语言中,在主程序和ISR之间共享一个不大于处理器自然字的带volatile限定符的对齐整数变量是否安全?是否保证不会发生读写中断?检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了关于volatile关键字的int之外,它只是为了防止编译器可能进行不正确的优化。这对线程安全没有帮助 使用给定大小的共享变量是否是线程安全的取决于编译器。无法保证访问是原子的。例如,编译器可能在进一步处理之前将变量加

在C语言中,在主程序和ISR之间共享一个不大于处理器自然字的带volatile限定符的对齐整数变量是否安全?是否保证不会发生读写中断?

检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了关于
volatile
关键字的
int
之外,它只是为了防止编译器可能进行不正确的优化。这对线程安全没有帮助

使用给定大小的共享变量是否是线程安全的取决于编译器。无法保证访问是原子的。例如,编译器可能在进一步处理之前将变量加载到寄存器中,然后将其写回内存。主要取决于CPU指令集。如果您想确定,您必须检查反汇编代码或在汇编程序中编写代码

否则,您可以使用bool创建“穷人的互斥对象”。这仅适用于不能被其他中断中断的微控制器ISR的特定情况。由于您知道ISR不能被中断,因此可以执行以下操作:

static volatile bool busy;
static volatile uint16_t shared;

void isr (void)
{
  if(!busy)
  {
    shared = something;
  }
}


void main (void)
{
  ...

  busy = true;
  do_something(shared);
  busy = false;

  ...
}

使用这种方法,
busy
shared
是否是原子的并不重要。无论在何处触发中断,
共享
都不会在访问过程中被破坏。

关于
volatile
关键字,它只是为了防止编译器可能进行的错误优化。这对线程安全没有帮助

使用给定大小的共享变量是否是线程安全的取决于编译器。无法保证访问是原子的。例如,编译器可能在进一步处理之前将变量加载到寄存器中,然后将其写回内存。主要取决于CPU指令集。如果您想确定,您必须检查反汇编代码或在汇编程序中编写代码

否则,您可以使用bool创建“穷人的互斥对象”。这仅适用于不能被其他中断中断的微控制器ISR的特定情况。由于您知道ISR不能被中断,因此可以执行以下操作:

static volatile bool busy;
static volatile uint16_t shared;

void isr (void)
{
  if(!busy)
  {
    shared = something;
  }
}


void main (void)
{
  ...

  busy = true;
  do_something(shared);
  busy = false;

  ...
}
使用这种方法,
busy
shared
是否是原子的并不重要。无论在何处触发中断,
共享
都不会在访问过程中被破坏。

答案是“有时”。如果ISR或主进程更改了变量,则您可以。但是,如果两者都操作变量,则

main
Var = Var + 10

ISR
Var = Var + 10
那谁知道呢?您可能会认为最终结果是var+20,但如果在程序集中,则顺序是

Main - Get Var
ISR -            Get Var
                 Add 10
                 Store Var
                 Return
       Add 10
       Store Var
那么最终结果将是10,而不是20

正如前面的海报所说,您需要一些保护代码来防止这种情况。

答案是“有时”。如果ISR或主进程更改了变量,则您可以。但是,如果两者都操作变量,则

main
Var = Var + 10

ISR
Var = Var + 10
那谁知道呢?您可能会认为最终结果是var+20,但如果在程序集中,则顺序是

Main - Get Var
ISR -            Get Var
                 Add 10
                 Store Var
                 Return
       Add 10
       Store Var
那么最终结果将是10,而不是20


正如前面的海报所说,您需要一些保护代码来防止这种情况。

不能保证任何通用整数变量都会以原子方式写入和读取。如果您需要这样的保证,您应该使用
sig\u atomic\u t
类型。这是唯一一种有这种保证的类型

根据C99标准7.14:

2定义的类型为

sig\u-atomic\u t

它是对象的(可能是易失性限定的)整数类型,可以作为原子实体访问,即使在存在异步中断的情况下也是如此


不能保证任何通用整数变量都将以原子方式写入和读取。如果您需要这样的保证,您应该使用
sig\u atomic\u t
类型。这是唯一一种有这种保证的类型

根据C99标准7.14:

2定义的类型为

sig\u-atomic\u t

它是对象的(可能是易失性限定的)整数类型,可以作为原子实体访问,即使在存在异步中断的情况下也是如此


volatile
关键字并不意味着原子性——这只是确保变量被显式读取,而不是假设没有更改。为了在没有任何其他保护机制的情况下实现安全共享访问,该变量必须是原子变量,并且声明为
volatile

编译器可以记录任何特定目标的原子类型,并且可以为此目的定义
sig\u atomic\u t


一般来说,假设编译器不会做任何反常的事情,并且在指令集允许原子读取的地方分割对齐的字读取,这可能是合理的。但是,在平台之间移植代码时应谨慎-此类低级代码应视为特定于目标且不可移植。

volatile关键字并不意味着原子性-这只是确保显式读取变量,并且不假设变量未更改。为了在没有任何其他保护机制的情况下实现安全共享访问,该变量必须是原子变量,并且声明为
volatile

编译器可以记录任何特定目标的原子类型,并且可以为此目的定义
sig\u atomic\u t

一般来说,假设编译器不会做任何反常的事情,并且在指令集允许原子读取的地方分割对齐的字读取,这可能是合理的。然而,在平台之间移植代码时应谨慎——此类低级代码应视为目标规范