C++ 读取和写入 int 是原子的吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/54188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are C++ Reads and Writes of an int Atomic?
提问by theschmitzer
I have two threads, one updating an int and one reading it. This is a statistic value where the order of the reads and writes is irrelevant.
我有两个线程,一个更新 int 一个读取它。这是一个统计值,其中读取和写入的顺序无关紧要。
My question is, do I need to synchronize access to this multi-byte value anyway? Or, put another way, can part of the write be complete and get interrupted, and then the read happen.
我的问题是,我是否需要同步访问这个多字节值?或者,换句话说,部分写入可以完成并被中断,然后读取发生。
For example, think of a value = 0x0000FFFF that gets incremented value of 0x00010000.
例如,考虑一个值 = 0x0000FFFF,它的增量值为 0x00010000。
Is there a time where the value looks like 0x0001FFFF that I should be worried about? Certainly the larger the type, the more possible something like this to happen.
是否有一段时间我应该担心该值看起来像 0x0001FFFF?当然,类型越大,这样的事情发生的可能性就越大。
I've always synchronized these types of accesses, but was curious what the community thinks.
我一直同步这些类型的访问,但很好奇社区的想法。
采纳答案by Adam Mitz
At first one might think that reads and writes of the native machine size are atomic but there are a number of issues to deal with including cache coherency between processors/cores. Use atomic operations like Interlocked* on Windows and the equivalent on Linux. C++0x will have an "atomic" template to wrap these in a nice and cross-platform interface. For now if you are using a platform abstraction layer it may provide these functions. ACEdoes, see the class template ACE_Atomic_Op.
起初,人们可能认为本机机器大小的读取和写入是原子的,但有许多问题需要处理,包括处理器/内核之间的缓存一致性。在 Windows 上使用 Interlocked* 等原子操作,在 Linux 上使用等效操作。C++0x 将有一个“原子”模板来将它们包装在一个漂亮的跨平台界面中。现在,如果您使用的是平台抽象层,它可能会提供这些功能。 ACE可以,请参阅类模板ACE_Atomic_Op。
回答by Skizz
Boy, what a question. The answer to which is:
男孩,这是什么问题。答案是:
Yes, no, hmmm, well, it depends
是的,不,嗯,嗯,这取决于
It all comes down to the architecture of the system. On an IA32 a correctly aligned address will be an atomic operation. Unaligned writes might be atomic, it depends on the caching system in use. If the memory lies within a single L1 cache line then it is atomic, otherwise it's not. The width of the bus between the CPU and RAM can affect the atomic nature: a correctly aligned 16bit write on an 8086 was atomic whereas the same write on an 8088 wasn't because the 8088 only had an 8 bit bus whereas the 8086 had a 16 bit bus.
这一切都归结为系统的架构。在 IA32 上,正确对齐的地址将是原子操作。未对齐的写入可能是原子的,这取决于使用的缓存系统。如果内存位于单个 L1 缓存行内,则它是原子的,否则不是。CPU 和 RAM 之间的总线宽度会影响原子性质:在 8086 上正确对齐的 16 位写入是原子的,而在 8088 上进行相同的写入则不是因为 8088 只有 8 位总线而 8086 具有16 位总线。
Also, if you're using C/C++ don't forget to mark the shared value as volatile, otherwise the optimiser will think the variable is never updated in one of your threads.
此外,如果您使用 C/C++,请不要忘记将共享值标记为 volatile,否则优化器会认为该变量永远不会在您的线程之一中更新。
回答by gabr
IF you're reading/writing 4-byte value AND it is DWORD-aligned in memory AND you're running on the I32 architecture, THEN reads and writes are atomic.
如果您正在读取/写入 4 字节值并且它在内存中是 DWORD 对齐的并且您在 I32 架构上运行,那么读取和写入是原子的。
回答by Anthony Williams
Yes, you need to synchronize accesses. In C++0x it will be a data race, and undefined behaviour. With POSIX threads it's already undefined behaviour.
是的,您需要同步访问。在 C++0x 中,这将是数据竞争和未定义的行为。对于 POSIX 线程,它已经是未定义的行为。
In practice, you might get bad values if the data type is larger than the native word size. Also, another thread might never see the value written due to optimizations moving the read and/or write.
实际上,如果数据类型大于本机字大小,您可能会得到错误的值。此外,由于优化移动读取和/或写入,另一个线程可能永远不会看到写入的值。
回答by Jason Cohen
You must synchronize, but on certain architectures there are efficient ways to do it.
您必须同步,但在某些架构上有有效的方法来做到这一点。
Best is to use subroutines (perhaps masked behind macros) so that you can conditionally replace implementations with platform-specific ones.
最好是使用子例程(可能被宏掩盖了),以便您可以有条件地用特定于平台的实现替换实现。
The Linux kernel already has some of this code.
Linux 内核已经有一些这样的代码。
回答by Andrew Stein
On Windows, Interlocked***Exchange***Add is guaranteed to be atomic.
在 Windows 上,Interlocked***Exchange***Add 保证是原子的。
回答by Andrew Stein
To echo what everyone said upstairs, the language pre-C++0x cannot guarantee anything about shared memory access from multiple threads. Any guarantees would be up to the compiler.
为了回应楼上每个人所说的,C++0x 之前的语言不能保证从多线程访问共享内存的任何事情。任何保证都取决于编译器。
回答by JeffV
Asside from the cache issue mentioned above...
除了上面提到的缓存问题......
If you port the code to a processor with a smaller register size it will not be atomic anymore.
如果将代码移植到具有较小寄存器大小的处理器,它将不再是原子的。
IMO, threading issues are too thorny to risk it.
IMO,线程问题太棘手了,不能冒险。
回答by kenny
回答by Leon Timmermans
No, they aren't (or at least you can't assume they are). Having said that, there are some tricks to do this atomically, but they typically aren't portable (see Compare-and-swap).
不,它们不是(或者至少你不能假设它们是)。话虽如此,有一些技巧可以原子地执行此操作,但它们通常不可移植(请参阅Compare-and-swap)。