我发现了类似的问题(即Is changing a pointer considered an atomic action in C?),但在编写指针时,我找不到能给出肯定的是/否答案的任何内容。
因此我的问题。我有一个带指针字段的struct指针数组。
例如
struct my_struct {
void *ptr;
};
struct my_struct *my_struct[10];
每个结构的指针字段由线程读取和写入。
例如
uint8_t index;
for(index = 0; index < 10; index++)
{
if(my_struct[index]->ptr != NULL)
{
my_struct[index]->ptr = NULL;
}
}
定期发生一个中断,它将读取(不写入,我不能使用锁,因为处理程序是时间关键的)一个或多个指针存储在我的结构数组中。
例如
void *ptr = my_struct[2]->ptr;
最终我不关心中断处理程序读取的指针是新的还是旧的;只是它没有被破坏。显然,以下操作不会是原子的
my_struct[index]->ptr = NULL;
但是,我能否确定如果发生中断并且读取&#34; my_struct [index] - &gt; ptr&#34;它不会被破坏?我怀疑这应该是真的,因为(1)指针应该完全适合寄存器(至少对于我的目标,MSP430)和(2)写一个寄存器很可能是一个原子指令。我的推理是否正确?
答案 0 :(得分:3)
在MSP430架构上(以及您可能使用的任何C编译器),指针读/写确实是原子的。因此,MSP430没有特定的std::atomic
(或等效)支持代码。
(对于大于本机字大小的类型,进行原子访问的唯一方法是禁用中断。)
在您的情况下,您需要关心的是编译器可能不知道并发访问,并重新排序自己对变量的访问。换句话说,除非您使用ptr
访问权限,否则可能会对volatile
的分配进行重新排序(或者,在极端情况下,优化掉)。您可以自己ptr
volatile
(void * volatile ptr;
)或add volatile when assigning it。
答案 1 :(得分:3)
TelosB使用msp430系列1 MCU,所有指针都是16位变量。 (还有其他系列的msp430无法保留。)通常,在msp430上访问16位变量是原子的。但是,如果有理由怀疑访问可能是未对齐的,编译器将在多个指令中分离对指针的访问(源:the TI forum):与x86不同,msp430只能在对齐的内存上进行字访问。
在上面提供的示例中,编译器没有理由怀疑,因为指针是没有对齐修饰符声明的结构的一部分。所以简短的故事就是你几乎肯定是安全的。不过,如果你要求正式保证,可能没有。另外,出于CL提及的原因,您应该使用volatile
。
答案 2 :(得分:2)
该芯片的RAM嵌入在芯片上。编译器同意指针大小的处理器,我认为你应该没问题 没有缓存,因此您甚至不必担心用于同步访问的围栏。
编辑:这里有很多其他答案,+1给所有答案。 OP的问题更多的是MSP430 / gcc编译器问题,而不是C语言问题,而且在我匆忙中,昨晚在关灯和睡觉之前,我给出了上述答案。我以前没有MSP430的经验,所以我上网并做了一些洞察,要求OP在他们的环境中检查几个常数并直接得出结论他们可能在规定的场景中没有任何担心。我习惯使用几乎不符合K&amp; R标准的嵌入式C编译器,更不用说C99或C11,但这种体验实际上早于C11,所以我不想问_Atomic
关键字是否可用(我应该有!)。所以这是另一回事:
如果您可以通过各种方式声明_Atomic(void*) ptr;
,请执行此操作。它将确保必要的对齐并生成以原子方式写入和读取指针值的代码。正如@Lundin指出的那样,在C语言方面,这是唯一确定的原子性。在没有_Atomic
,assert(sizeof(void*) == 2)
也assert(&(my_struct[index]->ptr) % 2 == 0)
的情况下,后者将确保指针值存储在对齐的地址位置。如果/当这些断言不成立时,由于未对准或指针大小超过处理器的字大小,您有可能读取部分写入的指针值。即使这些断言也不能保证,因为它们仅适用于使用DEBUG定义编译的代码。如果您认为需要始终验证这些约束,请改用if(expression)
。
@CL。关于volatile
关键字的观点也应该牢记,因为编译器可以自由地优化和重新排序访问,中断例程可能永远不会看到真正的指针值和除非在您的代码中使用任何数据之前将数据初始化为NULL,否则可能是导致某些非常严重,难以诊断的错误的原因。对于没有缓存且没有推测执行流水线的简单微处理器来说,这是不太可能的情况,但也不能排除它。因此,请使用volatile
关键字。
答案 3 :(得分:1)
由于我们谈论的是C,所以大多数发布的答案都是无稽之谈。无论指针类型有多大,MPC430都是16位MCU,就像16位地址总线一样。认为这在某种程度上使C代码成为原子是很简单的。
当你编写C时,任何变量(或指针)都可以存储在任何地方:寄存器,堆栈或完全优化。程序员无法控制这一点,这是一件好事。
每当您有可能将变量存储在堆栈中时,您也有机会获得多个指令。给定a = b
,a
,b
或两者都可以存储在任何位置(如果有的话)。如果它们中的任何一个存储在堆栈中,那么生成的机器代码很可能会产生类似的结果:
这种情况足以打破原子性 - CPU硬件无关紧要。即使在核心支持直接从堆栈写入其他存储器的情况下,也不能保证在单个指令中完成。周期。
即使您可以通过反汇编验证机器代码是原子的,也不一定是稳定状态。对代码进行更改,添加更多变量,再次链接,突然之前原子代码不再是原子的,反之亦然。反之亦然。
C语言中仅现有的原子性保证是:
_Atomic
关键字。