我对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类只使用原子操作,并分配给变量
答案 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;
按照步骤执行。
i
,子表达式(++i
)在增量后值评估。id
。 (这一步是非原子的)答案 2 :(得分:0)
kaka_ace,
不幸的是,在您提供的情况下,它不是原子的。
这就是为什么预增量操作是原子的,看看生成的程序集:
add %l0,1,%l0
(根据使用的组件可能略有不同)
但是那就是它。 1次操作。这就是为什么它是原子的。
当您为本地变量分配预增量时,至少有两条指令:
add %l0,1,%l0
st l0, [%fp-4]
这会产生至少两条指令,因此不再是原子的。
如果您有任何疑问,请与我们联系!