如果只写一个值,我需要原子的吗?

问题描述

假设我有多个线程访问同一内存位置。而且,如果有的话,它们都写入相同的值,而没有人读取它。 之后,所有线程都收敛(通过锁),然后才读取该值。我需要为此使用原子吗? 这是用于x86_64系统。该值为int32。

解决方法

根据§5.1.2.4 ¶25 and ¶4 of the official ISO C standard,使用非原子操作以无序方式写入同一内​​存位置的两个不同线程会导致undefined behavior。如果所有线程都写入相同的值,则ISO C标准对此规则也不例外。

尽管x86 / x64 CPU的Intel / AMD规范保证将32位整数写入4字节对齐地址是原子的,但除非ISO C标准不能保证这种操作是原子的,否则除非您使用的是ISO C标准保证是原子的数据类型(例如atomic_int_least32_t)。因此,即使您的线程根据ISO C标准将一个类型为int32_t的值写入4字节对齐的地址,您的程序仍然会导致未定义的行为。

但是,出于实际目的,只要满足对齐要求,就可以假定编译器正在生成原子执行该操作的汇编指令。

即使内存写入未对齐且CPU不会自动执行写入指令,您的程序仍可能会按预期运行。将写操作分为两个写操作无关紧要,因为所有线程都在写完全相同的值。

如果决定不使用原子变量,则至少应将变量声明为volatile。否则,编译器可能会发出汇编指令,从而使该变量仅存储在一个CPU寄存器中,从而使其他CPU永远看不到对该变量的任何更改。

因此,要回答您的问题:可能不必将变量声明为atomic。但是,仍然强烈建议使用。通常,对多个线程访问的变量的所有操作应为原子操作或受mutex保护。该规则的唯一例外是,如果所有线程都对该变量执行只读操作。

以不确定的行为玩耍很危险,通常不建议这样做。特别是,如果编译器检测到导致未定义行为的代码,则可以将该代码视为不可访问并对其进行优化。在某些情况下,某些编译器实际上会这样做。有关更多信息,请参见this very interesting post by Microsoft Blogger Raymond Chen

另外,请注意,写入同一位置(甚至相同的cache line)的多个线程可能会破坏CPU pipeline,因为x86 / x64体系结构保证必须强制执行strong memory ordering 。如果CPU的cache coherency protocol检测到由于另一个CPU写入同一高速缓存行而可能导致的内存顺序冲突,则可能必须清除整个CPU管道。因此,在所有线程都同步之后,将所有线程写入不同的内存位置(在不同的高速缓存行中,至少间隔64个字节)并分析写入的数据可能会更有效。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...