一个结构体 TsMyStruct 作为一些函数的参数给出:
typedef struct
{
uint16_t inc1;
uint16_t inc2;
}TsMyStruct;
void func1(TsMyStruct* myStruct)
{
myStruct->inc1 += 1;
}
void func2(TsMyStruct* myStruct)
{
myStruct->inc1 += 2;
myStruct->inc2 += 3;
}
func1 在非中断上下文中调用,func2 在中断上下文中调用。 func2 的调用堆栈以中断 vector 为起点。 C 编译器不知道可以调用 func2(但代码不被视为“未使用”代码,因为链接器在中断 vector 表内存部分需要它),因此可以优化一些在 func2 之外读取 myStruct->inc2 的代码,以防止 myStruct->inc2 从 ram 重新加载。对于 C 基本类型是正确的,但是对于 inc2 结构成员或某些数组...是正确的吗?函数参数也是如此吗?
作为一般规则,我可以说“在中断上下文中修改并在其他地方读取的每个内存区域(基本类型?或不是?)都必须声明为 volatile ”?
最佳答案
是的,在中断处理程序内部和外部使用的任何内存都应该是volatile
,包括结构和数组,以及作为函数参数传递的指针。假设您的目标是单核设备,则不需要额外的同步。
不过,您必须考虑到 func1
可能在任何地方被中断,如果您不小心,这可能会导致不一致的结果。例如,考虑一下:
void func1(volatile TsMyStruct* myStruct)
{
myStruct->inc1 += 1;
if (myStruct->inc1 == 4)
{
print(myStruct->inc1); // assume "print" exists
}
}
void func2(volatile TsMyStruct* myStruct)
{
myStruct->inc1 += 2;
myStruct->inc2 += 3;
}
由于中断是异步的,这可能会打印不同于 4 的数字。例如,如果 func1
在检查之后但在 print
调用之前被中断,就会发生这种情况。
关于c - C 中的 volatile 和变量修改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49418327/