Multithreading C++;11原子容器的螺纹安全
我正在尝试实现一个没有互斥锁的线程安全STL向量。因此,我完成了post并为原子原语实现了一个包装器 然而,当我运行下面的代码时,它显示出Multithreading C++;11原子容器的螺纹安全,multithreading,c++11,containers,atomic,atomicity,Multithreading,C++11,Containers,Atomic,Atomicity,我正在尝试实现一个没有互斥锁的线程安全STL向量。因此,我完成了post并为原子原语实现了一个包装器 然而,当我运行下面的代码时,它显示出失败两次(只有两个争用条件实例),因此它似乎不是线程安全的。我想知道我怎样才能解决这个问题 包装类 模板 结构原子变量 { std::原子; 原子变量():原子(T()){} 显式原子变量(T const&v):原子(v){} 显式原子变量(std::atomicconst&a):原子变量(a.load()){} 原子变量(原子变量常量和其他): 原子(oth
失败下面代码中的code>两次(只有两个争用条件实例),因此它似乎不是线程安全的。我想知道我怎样才能解决这个问题
包装类
模板
结构原子变量
{
std::原子;
原子变量():原子(T()){}
显式原子变量(T const&v):原子(v){}
显式原子变量(std::atomicconst&a):原子变量(a.load()){}
原子变量(原子变量常量和其他):
原子(other.atomic.load()){}
内联原子变量和运算符=(原子变量常量和rhs){
atomic.store(rhs.atomic.load());
归还*这个;
}
内联原子变量和运算符+=(原子变量常量和rhs){
atomic.store(rhs.atomic.load()+atomic.load());
归还*这个;
}
内联布尔运算符!=(原子变量常量和rhs){
return!(atomic.load()==rhs.atomic.load());
}
};
typedef原子变量AtomicInt;
功能和测试
//100个元素的向量。
向量公共(100,原子数(0));
void add10(向量和参数){
for(vector::iterator it=param.begin();
it!=param.end();++it){
*it+=AtomicInt(10);
}
}
void add100(向量和参数){
for(vector::iterator it=param.begin();
it!=param.end();++it){
*it+=AtomicInt(100);
}
}
void doParallelProcessing(){
//创建线程
标准::线程t1(添加10,标准::参考(通用));
标准::螺纹t2(add100,标准::参考(通用));
//加入他们
t1.join();
t2.连接();
//再次打印矢量
for(vector::iterator it=common.begin();
it!=common.end();++it){
if(*it!=AtomicInt(110)){
请注意
atomic.store(rhs.atomic.load() + atomic.load());
不是原子的
你有两个选择来解决它。
回忆录
1) 使用互斥锁
编辑正如注释中提到的T.C,这是不相关的,因为这里的操作将是load()然后load()然后store()(非松弛模式)-因此内存顺序在这里不相关
2) 使用内存顺序
memory_order_acquire:保证后续加载不会在当前加载或任何先前加载之前移动。
内存\u顺序\u释放:前面的存储不会移过当前存储或任何后续存储
我仍然不确定2,但我认为如果存储不是并行的,它会工作。只需将运算符+=写为:
inline AtomicVariable& operator+=(AtomicVariable const &rhs) {
atomic += rhs.atomic;
return *this;
}
在文档中:运算符+=是原子的
您的示例失败,因为以下执行场景是可能的:
Thread1-rhs.atomic.load()-返回10;Thread2-rhs.atomic.load()-返回100
Thread1-atomic.load()-返回0;Thread2-atomic.load-返回0
线程1-添加值(0+10=10);线程2-添加值(0+100)
Thread1-atomic.store(10);Thread2-atomic.store(100)
最后,在这种情况下,原子值可能是10或100,这取决于哪个线程首先执行atomic.store。您的AtomicVariable
不仅仅是毫无意义的-它是积极有害的。它使用std::atomic
,并使其某些操作非原子化。特别是,std::atomic::operator+=
是原子的,而ode>AtomicInt::operator+=
不是。这没有任何意义。是的,您显示了两条指令,但每一条指令都会触及其各自单独的内存位置。对于“非原子”的内容,应该对同一内存位置进行两次读取和/或修改。真正的问题在于operator+=
:atomic.store(rhs.atomic.load())+atomic.load())
这在同一个原子上调用load
和store
。@igortandtnik-这两条指令是问题所在。如果顺序是T1 load T2 load T2 store T1 load,则会出现问题,因为它们触及相同的内存。我不理解您的表示法。在任何情况下,您的示例都会从一块内存加载并存储到另一块内存;而y不要“触摸相同的记忆”是的,+=
不是原子的。但是你似乎把操作符=
,而不是操作符+=
,作为罪魁祸首-而且我看不出操作符=
有任何错误。事实上,标准::原子::操作符=
做的正是相同的事情。关于内存顺序的模糊手工操作是无用的,也是错误的。通过诽谤tstd::atomic
已经使用了最强的内存顺序(memory\u order\u seq\u cst
)。或者,就此而言,只需删除AtomicVariable
并直接使用std::atomic
。包装器似乎完全没有意义。现在就查看一下。@IgorTandetnik它是必需的,因为运算符没有隐式转换。可能是我编码错误,但我尝试过使用std::atomic,但它没有编译。@JohnJohn让AtomicVariable::operator+=
调用底层的atomic::operator+=
。如atomic+=rhs.atomic.load()
。或atomic.fecth\u add(rhs.atomic.load())
。这应该会有所帮助。请阅读位于的文档,我不知道,感谢您指出这一点。