在C语言中,在主程序和ISR之间共享易失性变量是否安全?
在C语言中,在主程序和ISR之间共享一个不大于处理器自然字的带volatile限定符的对齐整数变量是否安全?是否保证不会发生读写中断?检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了关于在C语言中,在主程序和ISR之间共享易失性变量是否安全?,c,embedded,volatile,C,Embedded,Volatile,在C语言中,在主程序和ISR之间共享一个不大于处理器自然字的带volatile限定符的对齐整数变量是否安全?是否保证不会发生读写中断?检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了检查编译器。ISR是非标准的。此外,C没有真正的“处理器自然字”概念,除了关于volatile关键字的int之外,它只是为了防止编译器可能进行不正确的优化。这对线程安全没有帮助 使用给定大小的共享变量是否是线程安全的取决于编译器。无法保证访问是原子的。例如,编译器可能在进一步处理之前将变量加
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
一般来说,假设编译器不会做任何反常的事情,并且在指令集允许原子读取的地方分割对齐的字读取,这可能是合理的。然而,在平台之间移植代码时应谨慎——此类低级代码应视为目标规范