C ++ 11在递增原子变量并将其赋值给其他值时,它是原子操作吗?

时间:2014-09-03 02:54:46

标签: c++ multithreading c++11 mutex atomic

我对c ++ 11上的原子操作感到困惑,

我知道原子变量自增量是原子操作,

但我使用赋值给其他值,只是怀疑它。

代码就像:

//....
static std::atomic<int> i; // global variable
//....
// in the thread
int id = ++i; 

在不同的线程上使用赋值时,id是唯一值吗?

测试代码:

#include <thread>
#include <mutex>
#include <atomic>
#include <iostream>

class A {
public:
    static int idGenerator;
    static std::mutex m;
    A () {
        // i know this operation will keep the id_ is unique
        std::lock_guard<std::mutex> lock(m);
        id_ = ++idGenerator; 
    }
   void F(std::string name) {
         std::cout << name << " " << id_ << std::endl;
    }
private:
    int id_;
};
int A::idGenerator = 0;
std::mutex A::m;

class B {
public:
    static int idGenerator;
    B () {
        // after self increment, is the assignment atomic? 
        id_ = (++idGenerator);
    }
   void F(std::string name) {
         std::cout << name << " " << id_.load() << std::endl;
    }
private:
    std::atomic<int> id_;
};
int B::idGenerator = 0;


void funcA() {
    A a2;
    a2.F("a2");
}

void funcB() {
    B b2;
    b2.F("b2");
}

int main() {
    A a1;
    B b1;
    std::thread t1(&funcA);
    std::thread t2(&funcB);
    a1.F("a1");
    b1.F("b1");

    t1.join();
    t2.join();
    return 0;
}

有三个主题,

班级使用lock_guard保持唯一。

B类只使用原子操作,并分配给变量

3 个答案:

答案 0 :(得分:9)

原子增量函数的规范提供了对其行为的重要洞察 - 来自http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith对于积分T类型:

T operator++();
T operator++() volatile;
T operator++( int );
T operator++( int ) volatile;

请注意,它们会按值返回T,并且永远不会从预增量返回通常的T&。出于这个原因,&#34;阅读&#34;后递增值的值不是第二个不同的操作,并且是原子增量操作本身的一部分。

另见&#34;返回值&#34;和&#34;注意&#34;上述链接页面上的文字。

答案 1 :(得分:4)

static std::atomic<int> i; // global variable
// in the thread
int id = ++i; 
  

在不同的线程上使用赋值时,id是唯一值吗?

是。 C ++原子变量确保以原子方式评估++i,因此不同线程上id的每个值都是唯一的。

表达式id = ++i;按照步骤执行。

  1. 原子增量i,子表达式(++i)在增量后值评估。
  2. 将“评估值”分配给id。 (这一步是非原子的)

答案 2 :(得分:0)

kaka_ace,

不幸的是,在您提供的情况下,它不是原子的。

这就是为什么预增量操作是原子的,看看生成的程序集:

 add %l0,1,%l0

(根据使用的组件可能略有不同)

但是那就是它。 1次操作。这就是为什么它是原子的。

当您为本地变量分配预增量时,至少有两条指令:

add %l0,1,%l0
st l0, [%fp-4]

这会产生至少两条指令,因此不再是原子的。

如果您有任何疑问,请与我们联系!