是C ++读写int原子吗?


80

我有两个线程,一个线程更新一个int,另一个读取它。这是一个统计值,其中读取和写入的顺序无关紧要。

我的问题是,是否仍然需要同步对此多字节值的访问?或者换一种说法,可以完成部分写入并使其中断,然后进行读取。

例如,考虑一个值为0x0000FFFF的值,该值的增量值为0x00010000。

是否有一段时间我应该担心该值看起来像0x0001FFFF?当然,类型越大,越可能发生这种情况。

我一直同步这些类型的访问,但是很好奇社区的想法。


5
真?我不在乎社区的想法。我会在乎事实是什么:)
11

1
在话题有趣的阅读:channel9.msdn.com/Shows/Going+Deep/...
ereOn

Answers:


47

最初,人们可能会认为对本机机器大小的读取和写入是原子的,但是要处理许多问题,包括处理器/内核之间的缓存一致性。在Windows上使用原子操作,例如Interlocked *,在Linux上使用等效操作。C ++ 0x将具有一个“原子”模板,以将它们包装在一个不错的跨平台界面中。现在,如果您正在使用平台抽象层,它可能会提供这些功能。 ACE可以,请参见类模板ACE_Atomic_Op


ACE_Atomic_Op的文件移动-它现在可以在找到dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/Atomic_Op.inl
拜伦

63

男孩,什么问题。答案是:

是的,不,嗯,这取决于

一切都取决于系统的体系结构。在IA32上,正确对齐的地址将是原子操作。未对齐的写入可能是原子的,这取决于所使用的缓存系统。如果内存位于单个L1缓存行中,则它是原子的,否则就不是。CPU和RAM之间的总线宽度可能会影响原子性质:在8086上正确对齐的16位写入是原子的,而在8088上进行相同的写入则不是,因为8088仅具有8位总线,而8086却具有8位总线。 16位总线。

同样,如果您使用的是C / C ++,请不要忘记将共享值标记为volatile,否则优化程序会认为该变量永远不会在您的线程之一中更新。


23
volatile关键字是不是在多线程程序有用stackoverflow.com/questions/2484980/...

5
@IngeHenriksen:我不相信该链接。
Skizz

:另一个来源,但不幸的是非常古老的(它早的std ::原子)web.archive.org/web/20190219170904/https://software.intel.com/...
最大巴勒克拉夫


9

是的,您需要同步访问。在C ++ 0x中,这将是一场数据竞赛,并且是不确定的行为。使用POSIX线程,它已经是不确定的行为。

实际上,如果数据类型大于本机字大小,则可能会得到错误的值。另外,由于优化会移动读取和/或写入,另一个线程可能永远看不到写入的值。


3

您必须同步,但是在某些体系结构上,有进行同步的有效方法。

最好是使用子例程(可能在宏后面隐藏),以便您可以有条件地将实现替换为特定于平台的实现。

Linux内核已经有一些这样的代码。



2

为了回应所有人在楼上所说的话,C ++ 0x之前的语言无法保证有关从多个线程访问共享内存的任何信息。任何保证都取决于编译器。


0

不,它们不是(或者至少您不能认为它们是)。话虽如此,有一些技巧可以自动完成,但是它们通常是不可移植的(请参阅Compare-and-swap)。


0

我同意很多人,尤其是杰森。在Windows上,很可能会使用InterlockedAdd及其朋友。


0

除了上面提到的缓存问题...

如果将代码移植到具有较小寄存器大小的处理器,它将不再是原子的。

IMO,线程问题太棘手,无法冒险。



0

让我们举个例子

int x;
x++;
x=x+5;

假定第一条语句是原子的,因为它转换为占用一个CPU周期的单个INC汇编指令。但是,第二个赋值需要几个操作,因此显然不是原子操作。

另一个例如

x=5;

同样,您必须分解代码以查看此处实际发生的情况。


2
但是编译器可以将其优化为x+=6
tc。

0

TC,我认为您使用常数(如6)的那一刻,指令将不会在一个机器周期内完成。尝试查看与x ++相比x + = 6的指令集


0

有人认为++ c是原子的,但是关注生成的程序集。例如,'gcc -S':

movl    cpt.1586(%rip), %eax
addl    $1, %eax
movl    %eax, cpt.1586(%rip)

要增加一个int,编译器首先将其加载到寄存器中,然后将其存储回内存中。这不是原子的。


1
如果只有一个线程正在向变量写入数据,那么这不会成为问题,因为不会产生任何撕裂。
Ben Voigt 2012年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.