为啥不能交换 std::atomic<T> ?

Posted

技术标签:

【中文标题】为啥不能交换 std::atomic<T> ?【英文标题】:Why can't std::atomic<T> be swapped?为什么不能交换 std::atomic<T> ? 【发布时间】:2020-05-07 11:20:19 【问题描述】:
#include <atomic>

int main()

    auto a = std::atomic_int(1);
    auto b = std::atomic_int(2);

    std::swap(a, b); // error

错误信息:

错误:没有匹配函数调用 'swap(std::atomic&, std::atomic&)'

为什么不能交换std::atomic&lt;T&gt;

【问题讨论】:

通过std::swap 交换不会是原子的,但我想知道为什么它没有成员swap... 交换它们时不需要是原子的。 相关? Atomic exchange of two std::atomic<T*> objects in a lock-free manner in C++11?; “问题是不可能跨两个原子对象进行原子操作,[...]”. atomic 不需要是原子的时候,为什么要首先使用它?考虑两个线程同时交换。单独的读写是原子的,但是交换后的结果可能会搞砸 例如在 move-ctor 中,成员变量是原子的。 @idclev463035818 【参考方案1】:

std::atomic 有一个已删除的复制构造函数,并且没有移动构造函数。

因此它既不是move assignable也不是move constructible

因此,std::swap 不能在任何 std::atomic 类型上调用。

参考:

https://en.cppreference.com/w/cpp/algorithm/swap

【讨论】:

a.exchange(b.exchange(a)); 怎么样?【参考方案2】:

这个问题有两个层面。

首先是简单而技术性的 - std::atomic 不能像其他答案中提到的那样移动构造或移动分配。

其次是这背后的基本原理——交换std::atomics 本身并不是原子的。并且由于std::atomics 用于多线程环境,添加swap 会由于可能的误解而导致广泛的错误(因为std::atomicswap,所以它本身就是原子的)。

总而言之 - 如果您不需要原子 swap,这可以很容易地使用提到的 exchanges 来完成。

【讨论】:

根据你的最后一段,我觉得这有点成为一个动机问题。更重要的是 - std::swap 在每种情况下基本上都是双重移动它只是交换两个值?如果是后者,我认为没有理由不完全像两个 exchange 调用那样实现它。不是试图在这里找到答案,而是试图大声说出潜在的问题。

以上是关于为啥不能交换 std::atomic<T> ?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++11 中以无锁方式原子交换两个 std::atomic<T*> 对象?

为啥即使删除了复制构造函数,std::atomic 也会从 C++17 编译?

如何在 std::atomic<T> 上实现一个简单的自旋锁,以便编译器不会对其进行优化?

理解 C++11 中的 std::atomic::compare_exchange_weak()

为啥标准库不以无锁方式为 8 字节以下的结构实现 std::atomic?

C++ 原子操作 std::atomic<int>