我听说在
if
上使用 switch
或 std::atomic
是错误的来源,因为一些与内存排序有关的参数
具体来说,代码如下:
void secondThreadFunc() {
puts( "Starting 2nd thread" );
branchVar = true;
}
int main() {
std::thread t( secondThreadFunc );
Sleep( 100 );
// Branching on a std::atomic considered dangerous due to memory ordering issues?
if( branchVar ) {
puts( "Branch true" );
}
else {
puts( "Branch false" );
}
t.join();
}
在
if( branchVar )
调用中植入竞争条件,被认为是不安全的编程。应始终使用 std::mutex
来锁定分支变量的访问
这是真的吗?有人可以向我解释为什么会这样吗?内存排序会导致
std::atomic
分支引发竞争条件吗?
在原子变量上进行分支没有任何问题。
通常有一个循环读取原子变量,如果读取为某个值则退出。这就是所谓的“旋转”。自旋基本上是原子变量上的向后分支。 自旋常用于同步原语的实现中,包括
std::mutex
或
std::call_once
。 (您可能无法直接在 STL 实现中看到它,因为这通常是在较低级别中完成的)。当直接在if
或
switch
表达式中使用原子变量时,会发生隐式转换,相当于不带参数的.load()
,并且内存顺序隐式为memory_order_seq_cst
。这是最安全的内存顺序,因此不会引入任何新问题。原子的使用可能仍然存在问题,因为可能会与其他数据发生数据竞争,但这取决于您的代码,与原子本身没有任何关系。
使用 std::mutex
等的建议可能来自这样的事实:
std::atomic
本身仅为其自身提供原子性。因此,如果您在线程中修改原子数据和其他一些数据,然后在原子上进行分支,则可能会出现与其他数据修改相关的数据争用。或者,如果一切都正确的话,可能不会出现数据竞争。