如何交换两个 std::atomic 变量?

Sté*_*ane 3 c++ stdatomic

我有两个std::atomic变量,如下所示:

std::atomic<bool> b1;
std::atomic<bool> b2;
Run Code Online (Sandbox Code Playgroud)

在代码中的某个时刻我需要交换它们。它在创建线程之前运行,所以我知道只有主线程,没有其他人试图读/写这些变量。但:

std::swap(b1, b2);
Run Code Online (Sandbox Code Playgroud)

这导致:

[...] MSVC\14.24.28314\include\utility(61,1): error C2280: 'std::atomic<bool>::atomic(const std::atomic<bool> &)': attempting to reference a deleted function
[...] MSVC\14.24.28314\include\atomic(1480): message : see declaration of 'std::atomic<bool>::atomic'
[...] MSVC\14.24.28314\include\atomic(1480,5): message : 'std::atomic<bool>::atomic(const std::atomic<bool> &)': function was explicitly deleted
Run Code Online (Sandbox Code Playgroud)

我不确定为什么复制构造函数被删除。所以我使用的解决方案是使用带有第三个变量的旧式交换:

const bool tmp = b1;
b1 = b2.load();
b2 = tmp;
Run Code Online (Sandbox Code Playgroud)

但现在我很好奇:为什么std::atomic删除了 的复制构造函数?

(实际代码比两个单个变量更复杂std::atomic<bool>,但我尝试将其简化为这个问题的简单情况。)

Sha*_*ger 5

你意识到你所做的不是原子的,对吧?从加载时刻到设置b1时刻,它具有各种可能的数据竞争。b2

大概被禁止的原因swap是不可能执行修改两个不相关的内存地址的原子操作(至少,移植性不足以支持它作为语言标准),所以它拒绝通过默默地使用非原子来欺骗你交换。

方便的是,还有其他原因禁止复制构造,因此默认实现std::swap被阻止作为禁止复制构造的副作用,所以他们所要做的就是拒绝swap自己提供一个说谎的实现。

  • @Stéphane:所以你的问题是“为什么我不能做一件在所有情况下都允许该类型有用的事情,即使我小心翼翼地只在安全的情况下才这样做,并且类型是完全没有意义吗?” 有点答案了;对于标准委员会而言,支持仅在不需要原子时才安全、而在需要原子时则危险的原子场景将是一个非常糟糕的设计决策。 (4认同)
  • 不,这根本不是我的问题。 (2认同)