一元增量算子的原子行为

时间:2018-12-18 11:30:00

标签: c++ c increment atomic

在某些地方,我读到一元运算符本质上是原子的,因此可以在多线程环境中使用它们。为了确认这一点,我在

中编写了两个单独的程序。
  1. 我使用了变量x,并使用一元运算符++ x进行了递增
  2. 我使用了变量x,并使用x = x + 1递增

我比较了两个程序的反汇编,发现没有区别。请提供您的意见。

9 个答案:

答案 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根本不保留这些操作,需要您正确地使用这些操作。

请注意:++xx = 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的类型。

  1. 如果平台为16或8位时x是32位整数,则执行'x ++'操作 肯定会进行多种操作
  2. x甚至可能不是基本类型,x可能是Class的一个实例,其中operator ++要做的事情要复杂得多,而只是增加整数

答案 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 的一部分。因此问题标题与正文不一致。

即使像& * + - ~ !这样的一元运算符也不是原子的,因为对对象的访问(认为+)需要读取多个操作码。