+=、|=、&= 等是原子的吗?

发布于 2024-08-25 18:39:04 字数 325 浏览 5 评论 0原文

+=|=&= 等“修改”运算符是原子的吗?

我知道 ++ 是原子的(如果你“同时”在两个不同的线程中执行 x++; ,你总是会得到 x 增加2,与关闭优化的 x=x+1 相反。)

我想知道的是 variable |=constant 等是否是线程安全的,或者我是否这样做必须用互斥锁来保护它们吗?

(...或者它依赖于CPU?在这种情况下,它在ARM上怎么样?)

Are the "modify" operators like +=, |=, &= etc atomic?

I know ++ is atomic (if you perform x++; in two different threads "simultaneously", you will always end up with x increased by 2, as opposed to x=x+1 with optimization switched off.)

What I wonder is whether variable |= constant, and the likes are thread-safe or do I have to protect them with a mutex?

(...or is it CPU-dependent? In this case, how is it on ARM?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

疧_╮線 2024-09-01 18:39:04

您错了。不能保证 ++ 是原子的,复合赋值运算符也不能保证,甚至任何 C++ 操作也不能保证。

You are wrong. There is no guarantee that ++ is atomic and neither is there for the compound assignment operators, or indeed for any C++ operation.

她说她爱他 2024-09-01 18:39:04

x++ 通常用 3 条指令实现:将 X 读入寄存器,递增它,然后将其写回内存。

您的线程可能会在其中任何一个之间被抢占。

x++ is often implemented in 3 instructions: Read X into a register, Increment it, and Write it back to memory.

Your thread may be pre-empted in between any of those.

网名女生简单气质 2024-09-01 18:39:04

为了使值的变化在核心之间可见,+=(例如)必须加载该值,添加增量,然后存储它。这意味着该操作将不是原子的

为了确保原子性,您需要对操作进行适当的锁定。

For the change in value to be visible across cores, a += (for instance) would have to load the value, add the increment and then store it. This means that the operation will not be atomic.

To ensure atomicity you'd need to put appropriate locking around the operation.

硪扪都還晓 2024-09-01 18:39:04

C 或 C++ 中的 No 运算符保证是原子的。他们可能在您的平台上,但您不确定。通常,唯一的原子操作是测试和设置指令,该指令通常在大多数现代 CPU 上以某种形式提供,作为实现信号量的基础。

No operator in C or C++ is guaranteed to be atomic. They might be on your platform, but you won't know for sure. Typically, the only operation that is atomic is the an instruction Test and Set, which is usually available on most modern CPUs in some form as the basis for implementing semaphores.

奢欲 2024-09-01 18:39:04

不,它们不是原子的!
如果您需要对原始类型进行原子操作,并且您使用的是 Linux,则可以查看此处: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 和/或atomic.h...

No, they're not atomic!
If you need atomic operations on primitive types, and you're using linux, you can take a look here: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html and/or atomic.h...

情愿 2024-09-01 18:39:04

++ 在您的编译器/平台上可能是原子的,但在 C++ 规范中它没有定义为原子的。

如果您想确保以原子方式修改值,您应该使用适当的方法,例如 Windows 上的 Interlocked*。

所有其他例程都相同。如果您想要原子操作,您应该使用适当的调用,而不是标准的调用。

++ might be atomic on your compiler/platform, but in the c++ specs it is not defined to be atomic.

If you want to make sure to modify a value in an atomic way, you should use the appropiate methods, like Interlocked* on windows.

Same for all the other routines. If you want atomic operations, you should use the appropiate calls, not the standard ones.

童话 2024-09-01 18:39:04

它既依赖于编译器又依赖于CPU。一些指令集为这些提供原子指令(在机器大小的整数上)。

但是,不能保证您的编译器将使用这些指令并且不会以非线程安全的方式优化您的代码。您需要在汇编中编写例程或使用提供原子性的编译器特定技术(例如内联)(或使用使用其中一种技术的库)。


特别是在 ARM 上:
ORR/ADD/AND 指令采用两个操作数并将结果放入寄存器中。任一操作数都可以是与结果寄存器相同的寄存器,因此它们可以用作原子 |=、+=、&=。

当然,结果放入寄存器中,并且第一个操作数也必须来自寄存器,因此您必须确保寄存器加载是自动完成的。

It's both compiler and CPU dependent. Some instruction sets provide atomic instructions for these (on machine-sized ints).

However, there's no guarantee that you compiler will use those instructions and won't optimize your code in a non-threadsafe way. You need to either write routine in assembly or use a compiler specific technique (such as instrinsics) that provides atomicity (or use a library that uses one of those techniques).


Specifically on ARM:
The ORR/ADD/AND instructions take two operands and place the result in a register. Either operand can be the same register as the result register, so they can used as an atomic |=, +=, &=.

Of course, the result is put in a register and the first operand must also come from a register, so you'll have to make sure the register loads are done atomically.

涙—继续流 2024-09-01 18:39:04

它们不仅不像所有操作那样是原子的,而且可以产生非常有趣的结果。例如,如果编译器看到它写入 x,则允许使用 x 作为临时变量,而不是使用寄存器或堆栈空间。这意味着 x 可能暂时包含任何值,而不仅仅是对 x 有意义的值

http://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-c​​ould-possible-出错了

Not only are they not atomic, like all operations, but they can have very interesting results. For example, if the compiler sees that it writes to x, it is allowed to use x as a temporary variable, rather than using up registers or stack space. This means x may temporarily contain ANY value, not just values that make sense for x

http://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong

财迷小姐 2024-09-01 18:39:04

此处有一个重复,需要更新。 “新”C11 语言启用了原子属性,该属性承认:

_Atomic int a;
...
a += 3

可以编译成(原子)无界循环。感谢各位的礼物标准,我真的希望你们没有。

1:在某些架构中,原子操作只能在支持某些访问协议的内存上进行。例如,ARMv7、MIPS 将序列转换为:

do {
    x = LoadLinked(a) + 3;
} while !StoreConditional(x, &a);

但对于某些内存/缓存类型,LoadLinked/StoreConditional 未定义。享受调试的乐趣。

2:相关的是错误共享,这是 LoadLinked、StoreConditional 在缓存行(例如 32、64、256 字节)而不是子块上操作的产物。所以:
_原子 int a[4];
可能需要 4* 缓存行大小(即 1024 字节)才能安全地允许对 a[n] 和 a[n+1] 进行同时原子操作,因为 4 个 cpu 可能会争先恐后地更新 a[0..3],但永远不会成功。

希望下一个标准能够认识到属性修饰的固有缺陷,并恢复 c89 作为合法的 C 标准。

A duplicate was directed here, and this needs an update. The “new” C11 language enables an atomic attribute which admits that:

_Atomic int a;
...
a += 3

can be compiled into an (atomic) unbounded loop. Thanks for the gift standards folks, I really wish you hadn’t.

1: in some architectures, atomic operations are only possible on memory which supports certain access protocols. ARMv7, MIPS for example turn the sequence into:

do {
    x = LoadLinked(a) + 3;
} while !StoreConditional(x, &a);

but LoadLinked/StoreConditional is undefined for some memory/cache types. Enjoy debugging that.

2: Related is false sharing which is an artifact of LoadLinked, StoreConditional operating upon cache lines (eg. 32, 64, 256 bytes) not sub-blocks. So:
_Atomic int a[4];
might require 4* cache line size (thus 1024 bytes) to safely permit simultaneous atomic operations on a[n] and a[n+1], because 4 cpu’s could be fighing to update a[0..3], but never succeeding.

Hopefully the next standard will recognize the inherent failure of attribute decoration, and reinstate c89 as the rightful C standard.

梦在深巷 2024-09-01 18:39:04

值得一提的是,这些运算符可以重载,因此当然不能保证它们对于所有类都是原子的。

It's worth mentioning that these operators can be overloaded, so there can certainly be no general guarantee that they are atomic for all classes.

花想c 2024-09-01 18:39:04

即使 ++ 是原子操作,也不意味着两个线程执行 ++x 会导致 x 恰好高出 2。您必须以某种方式同步线程,否则它们不一定会看到彼此的更改。

Even if ++ is an atomic operation, that does not imply that two threads doing ++x will result in x being exactly two higher. You have to synchronize the threads somehow, or otherwise they won't necessarily see each other's changes.

來不及說愛妳 2024-09-01 18:39:04

你必须保护你的变量,例如使用互斥锁

You have to protect your variable, with a mutex for instance

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文