根据en.cppreference.com,std::atomic_exchange
和std::atomic_store
相当于线程安全std::swap
。但这不是我用g ++或clang ++获得的行为。
它打印了这个:
std::atomic_store
a: 0x1ed2c30 0
b: 0x1ed2c50 1
a: 0x1ed2c50 1
b: 0x1ed2c50 1
std::atomic_exchange
a: 0x1ed2c50 0
b: 0x1ed2c30 1
a: 0x1ed2c30 1
b: 0x1ed2c30 1
这是为什么?难道我做错了什么?我误读了文档吗?
#include <iostream>
#include <memory>
int main()
{
{
std::cout << "std::atomic_store\n\n";
auto a = std::make_shared<int>(0);
auto b = std::make_shared<int>(1);
std::cout
<< "a: " << a.get() << '\t' << *a << '\n'
<< "b: " << b.get() << '\t' << *b << '\n' << std::endl;
std::atomic_store(&a, b);
std::cout
<< "a: " << a.get() << '\t' << *a << '\n'
<< "b: " << b.get() << '\t' << *b << '\n' << std::endl;
}
{
std::cout << "std::atomic_exchange\n\n";
auto a = std::make_shared<int>(0);
auto b = std::make_shared<int>(1);
std::cout
<< "a: " << a.get() << '\t' << *a << '\n'
<< "b: " << b.get() << '\t' << *b << '\n' << std::endl;
std::atomic_exchange(&a, b);
std::cout
<< "a: " << a.get() << '\t' << *a << '\n'
<< "b: " << b.get() << '\t' << *b << '\n' << std::endl;
}
}
答案 0 :(得分:11)
这种描述有点误导。
它说,例如,
template<class T>
void atomic_store( std::shared_ptr<T>* p,
std::shared_ptr<T> r );
“有效”会p->swap(r)
。这一点确实如此(实际上标准也是如此)。
但是,r
是一个由值传递的函数参数,因此在函数返回之前被销毁。它不会影响调用者中的任何内容。
答案 1 :(得分:2)
std::atomic_exchange
不交换a和b,它将a设置为b并返回a的前一个值。
你可以这样做:
b = std::atomic_exchange(&a, b);
这将按预期工作(交换a和b的指针),但这不是线程安全的:如果多个线程同时访问对象b
,则这是未定义的行为。你不能做得更好,因为共享指针是一个复杂的结构,通常包含两个数据成员(两个指针)。由于无原子锁定交换需要硬件支持,因此仅适用于基本类型(整数和指针)。
答案 2 :(得分:1)
令我困惑的是,为什么“比较和交换”&#39;其中有swap
个。它不会交换任何东西。它设置check passess时的值,如果检查失败则返回当前值。因此,绝不是atomic_exchange与std :: swap相同。
相反,它是一种检查和设置模式,所以我总是喜欢CAS来表示比较和设置。
答案 3 :(得分:0)
看起来我想要的行为最接近的是:
std::atomic_store(
&b,
std::atomic_exchange(
&a,
b
)
);
然而,这不是严格的原子。 a
和b
可以在几分之一秒内指向相同的地址。
在我的情况下,只要这两种行为都指向有效的,定义良好的对象,这种行为是可以接受的。