简体   繁体   English

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

[英]C++11 when increment the atomic variable, and assign it to other value, is it atomic operation?

i'm confused about the atomic operation on c++11, 我对c ++ 11上的原子操作感到困惑,

i know the atomic variable self increment is atomic operation, 我知道原子变量自增量是原子操作,

but i use the assignment to other value, just doubt it. 但我使用赋值给其他值,只是怀疑它。

the code just like: 代码就像:

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

when using the assignment at different threads, is the id unique value? 在不同线程使用赋值时,id是唯一值吗?

the test code: 测试代码:

#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;
}

there are three threads, 有三个线程,

A class use lock_guard keep unique. 一个类使用lock_guard保持唯一。

B class just use atomic operation, and assign to the variable B类只使用原子操作,并赋值给变量

The specification of the atomic increment functions give a crucial insight into their behaviour - from http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith for Integral T types: 原子增量函数的规范提供了对其行为的重要见解 - 来自http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith的Integral T类型:

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

Notice they return a T by value, and never return the usual T& from a pre-increment. 注意它们返回一个T值,并且永远不会从预增量返回通常的T& For that reason, the "read" of post-incremented value is not a second distinct operation, and is part of the atomic increment operation itself. 出于这个原因,后递增值的“读取”不是第二个不同的操作,并且是原子增量操作本身的一部分。

See also the "Return Value" and "Note" text on the above-linked page. 另请参见上述链接页面上的“返回值”和“注释”文本。

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

when using the assignment at different threads, is the id unique value? 在不同线程使用赋值时,id是唯一值吗?

Yes. 是。 C++ atomic variables ensure that ++i will be evaluated atomically, so each values of id on different threads are unique. C ++原子变量确保++i将以原子方式进行求值,因此不同线程上id每个值都是唯一的。

The expression id = ++i; 表达式id = ++i; is executed following steps. 按照以下步骤执行。

  1. atomically increment i , and sub-expression( ++i ) is evaluated post-increment value. 原子地递增i ,并且子表达式( ++i )在递增后的值处被评估。
  2. assign "evaluated value" to id . 将“评估值”分配给id (this step is non-atomically) (这一步是非原子的)

kaka_ace, kaka_ace,

Unfortunately in the case you provided, it isn't atomic. 不幸的是,在您提供的情况下,它不是原子的。

Here's the reason why the pre-increment operation is atomic, look at the assembly generated: 这就是为什么预增量操作是原子的,看看生成的程序集:

 add %l0,1,%l0

(might vary a little bit depending on the assembly used) (可能会有所不同,具体取决于使用的组件)

But that's it. 但就是这样。 1 operation. 1次操作。 That's why it's atomic. 这就是为什么它是原子的。

When you're assigning a pre-increment to a local variable, that's at least two instructions: 当您为局部变量分配预增量时,至少有两条指令:

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

That generates at least two instructions, and hence is no longer atomic. 这会产生至少两条指令,因此不再是原子的。

Please let me know if you have any questions! 请让我知道,如果你有任何问题!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM