在主程序和C中的ISR之间共享一个不大于处理器自然字的对齐整数变量,使用volatile限定符是否安全?是否保证不会发生撕裂的读写操作?
答案 0 :(得分:3)
volatile
关键字并不意味着原子性 - 这只是确保显式读取变量而不是假设没有更改。对于没有任何其他保护机制的安全共享访问,变量必须是原子的并且声明为volatile
。
编译器可以记录任何特定目标的原子类型,并可以为此目的定义sig_atomic_t
。
一般来说,假设你的编译器不会做任何反常操作并将指令集允许原子读取的对齐字读取分开也许是合理的。但是在平台之间移植代码时应该谨慎 - 这种低级代码应该被视为特定目标和非移动代码。
答案 1 :(得分:1)
关于volatile
关键字,它可以防止编译器可能出现的错误优化。它对线程安全没有帮助。
使用给定大小的共享变量是否是线程安全的取决于编译器。无法保证访问是原子的。例如,编译器可能会在进一步处理之前将变量加载到寄存器中,然后将其写回内存。主要取决于CPU指令集。如果您想确定,则必须检查反汇编代码或在汇编程序中编写代码。
否则,你可以制造一个穷人的互斥体"与布尔。 这仅适用于不能被其他中断中断的微控制器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
是否是原子的并不重要。无论中断在何处触发,shared
都不会在访问中途被破坏。
答案 2 :(得分:1)
无法保证任何通用整数变量将以原子方式写入和读取。如果您需要这样的保证,您应该使用False
类型。这是唯一有这种保证的类型。
来自C99标准7.14:
2定义的类型是
sig_atomic_t
即使存在异步中断,也可以作为原子实体访问的(可能是volatile限定的)整数类型的对象。
答案 3 :(得分:0)
检查您的编译器。 ISR是非标准的。此外,C没有真正的概念"处理器自然词"除了int
之外。
答案 4 :(得分:0)
答案是"有时"。如果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
正如之前的海报所说,你需要有一些保护代码来防止这种情况发生。