为啥不能交换 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<T>
?
【问题讨论】:
通过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::atomic
s 本身并不是原子的。并且由于std::atomic
s 用于多线程环境,添加swap
会由于可能的误解而导致广泛的错误(因为std::atomic
有swap
,所以它本身就是原子的)。
总而言之 - 如果您不需要原子 swap
,这可以很容易地使用提到的 exchange
s 来完成。
【讨论】:
根据你的最后一段,我觉得这有点成为一个动机问题。更重要的是 -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()