在某些地方,我读到一元运算符本质上是原子的,因此可以在多线程环境中使用它们。为了确认这一点,我在
中编写了两个单独的程序。我比较了两个程序的反汇编,发现没有区别。请提供您的意见。
答案 0 :(得分:13)
在某些地方,我读到一元运算符本质上是原子的,因此可以在多线程环境中使用它们。
该消息来源是完全错误的。您需要使用std::atomic
(或C等效项)来实现原子性-一元运算并不特殊。
我比较了两个程序的反汇编,发现没有区别
这并不意味着生成的操作是原子的。没什么区别,因为任何体面的编译器都会将x=x+1
和++x
优化到同一程序集中(假定内置类型)。
答案 1 :(得分:5)
一元运算符必须是原子的说法是一个神话。
例如,++x
需要对x
进行读写操作,从而打开了数据竞争的机会。
++x
编译为与x = x + 1
相同的代码这一事实无关紧要。
如果要避免数据争用,请使用原子类型,如果没有合适的原子类型,则使用互斥单元。为避免疑问,int
不一定是原子类型。
答案 2 :(得分:5)
在编写跨平台C ++时,仅在使用std::atomic<>
时具有原子行为。
在某些平台(例如Intel 64bit)上,处理器确实保证inc
是原子的。但是,请不要编写依赖于此的代码!作为您将来的调试器,我想知道哪些数据打算通过线程共享,哪些不是。
使用std::atomic<int>
可能需要花费更多的时间来编写,但是,它可以通过回退到平台要求(std::atomic::is_lock_free)或通过以下方式来确保一切(在每个平台上)都具有原子行为:明确地在访问周围设置一个锁。它还会插入防护措施,以确保其他处理器内核的缓存无效(如果平台需要这样做的话)。
实际上,对于Intel 64位,这应该为您提供相同的程序集,否则,请在编译器上记录错误。
同时,某些带有int的操作可能不是原子操作(operator * =),std::atomic
根本不保留这些操作,需要您正确地使用这些操作。
请注意:++x
和x = x+1
是不同的操作,它们可能已针对同一程序集进行了优化。考虑到非原子平台的要求,第二个突然是一个需要几天才能解决的错误。
答案 3 :(得分:4)
在某些地方,我读到一元运算符本质上是原子的,因此它们 可以在多线程环境中使用。
那是错误的。例如,x++
要求加载x
,添加和存储x
。这些说明本质上不是原子的。
答案 4 :(得分:2)
不是。即使可能,https://en.cppreference.com/w/cpp/atomic/atomic#Type_aliases会有什么原因呢?
我认为它们可能意味着在这种操作上进行的计算通常非常短,因此很可能永远不会出现竞争条件,这在实时代码中非常正确,在实时代码中您不会同时在4个for循环中计算x ++。 / p>
答案 5 :(得分:2)
您没有指定x的类型。
答案 6 :(得分:1)
操作stronglr的原子性取决于目标系统。一元操作在RISC微控制器等RMW系统上可能不是原子的。
这个问题没有一个通用的答案。
答案 7 :(得分:0)
您对生成的代码进行了假设,如果仅生成一条指令,是的,它将是原子的,否则,不会。
在您的情况下,这假设目标处理器具有指令inc <address>
,编译器将生成指令。
答案 8 :(得分:0)
一元算子的原子行为
在C中,前/后修订from collections import Counter
name = 'Annuu'
c = Counter(name.lower())
mc = c.most_common()
max_count = mc[0][1]
for i, x in enumerate(mc):
if x[1] < max_count:
break
print(mc[:i+1]) # [('n', 2), ('u', 2)]
不是一元运算符,例如++
。但是 unary-expression 的一部分。因此问题标题与正文不一致。
即使像& * + - ~ !
这样的一元运算符也不是原子的,因为对对象的访问(认为+
)需要读取多个操作码。