C++ 是+;=,|=&;=等等原子?

C++ 是+;=,|=&;=等等原子?,c++,c,operators,thread-safety,atomic,C++,C,Operators,Thread Safety,Atomic,像+=,|=,&=等“修改”操作符是原子的吗 我知道++是原子的(如果你在两个不同的线程中“同时”执行x++;,你最终总是会得到x增加2,而不是关闭优化后的x=x+1) 我想知道的是variable |=constant等是线程安全的,还是必须使用互斥锁来保护它们 (…还是它依赖于CPU?在这种情况下,它在ARM上是如何工作的?你错了。不能保证++是原子的,对于复合赋值运算符,或者对于任何C++操作,都不存在。< p>对于在内核中可见值的变化,A+=(例如)必须加载值,添加增量,然后存储它。这意

+=
|=
&=
等“修改”操作符是原子的吗

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

我想知道的是
variable |=constant
等是线程安全的,还是必须使用互斥锁来保护它们


(…还是它依赖于CPU?在这种情况下,它在ARM上是如何工作的?

你错了。不能保证++是原子的,对于复合赋值运算符,或者对于任何C++操作,都不存在。

< p>对于在内核中可见值的变化,A+=(例如)必须加载值,添加增量,然后存储它。这意味着操作将不是原子的


为了确保原子性,你需要在操作周围放置适当的锁定。

++可能是你的编译器/平台上的原子,但是在C++规范中,它不是定义为原子的。 如果要确保以原子方式修改值,应使用适当的方法,如windows上的Interlocked*


所有其他例程都是一样的。如果你想要原子操作,你应该使用适当的调用,而不是标准的调用。C++中的< < > > P > <强> > < >强> >操作符保证为原子。他们可能在你的平台上,但你不能确定。通常,唯一的原子操作是指令测试和设置,它通常以某种形式在大多数现代CPU上可用,作为实现信号量的基础。

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


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

值得一提的是,这些操作符可能会被重载,因此不能保证它们对于所有类都是原子的。

不,它们不是原子的!
如果您需要对基本类型执行原子操作,并且您正在使用linux,那么您可以在这里查看:和/或atomic.h..

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

您必须保护您的变量,例如使用互斥锁,它既依赖于编译器,也依赖于CPU。某些指令集为这些指令提供原子指令(在机器大小的INT上)

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


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


当然,结果放在寄存器中,第一个操作数也必须来自寄存器,因此您必须确保寄存器加载是以原子方式完成的。

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

此处指示了一个副本,需要更新。“新”C11语言支持原子属性,该属性允许:

_Atomic int a;
...
a += 3
可以编译成(原子)无界循环。谢谢你们的礼物,我真希望你们没有

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

do {
    x = LoadLinked(a) + 3;
} while !StoreConditional(x, &a);
但对于某些内存/缓存类型,LoadLink/StoreConditional未定义。享受调试

2:Related是假共享,它是LoadLinked、StoreConditional在缓存线(例如32、64、256字节)而不是子块上操作的产物。因此: _原子intα[4]; 可能需要4*缓存线大小(因此1024字节)才能安全地允许在[n]和[n+1]上同时执行原子操作,因为4个cpu可能正在运行以更新[0..3],但从未成功


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

这意味着这是特定于CPU的。在允许
inc[address]
的单核体系结构上,这绝对是原子的。至少在C++0x之前:“此子句描述用于细粒度原子访问的组件。此访问通过对原子对象的操作提供。”[n3035草案中的29.1/1]。@SF不,不是。它是特定于编译器的。仅仅因为CPU体系结构有一条指令,并不意味着编译器将以您认为应该的方式使用它,如果它确实使用它的话。即使编译器可以生成原子增量,x++是否可以是原子的可能取决于x的数据类型。例如,在SF的目标上,如果x是“long-long”,则x的增量将不是原子的,如果它是另一个整数类型,则可能取决于特定的ARM体系结构和数据对齐方式。@SF:这非常具体。如果编译器选择不使用该指令怎么办?如果/当您升级到多核系统时会发生什么?对于没有
inc
指令的体系结构呢?一般来说,
++
不是原子的。你刚刚发现了一个狭义的特例,它不是一个问题,它们不能重载整数,我对此进行了分析