Reputation: 1243
According to en.cppreference.com, std::atomic_exchange
and std::atomic_store
are equivalent to a thread-safe std::swap
. But that's not the behavior that I'm getting with g++ or clang++.
Problem live on coliru. (see below)
It prints this though:
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
Why is this? Am I doing something wrong? Have I misread the documentation?
#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;
}
}
Upvotes: 3
Views: 3719
Reputation: 137315
That description is somewhat misleading.
It says, e.g.,
template<class T>
void atomic_store( std::shared_ptr<T>* p,
std::shared_ptr<T> r );
"effectively" does p->swap(r)
. Which is true as far as it gets (and is actually what the standard says, too).
But, r
is a function argument passed by value, and so is destroyed before the function returns. It doesn't affect anything in the caller.
Upvotes: 11
Reputation: 9292
std::atomic_exchange
does not swap a and b, it sets a to b and returns the previous value of a.
You could do :
b = std::atomic_exchange(&a, b);
This would work as you expect (exchange the pointers of a and b) but this is not thread safe : if multiple threads access the object b
at the same time, this is undefined behavior. You cannot do better since a shared pointer is a complex struct containing typically two data members (two pointers). As atomic lock-free exchange requires hardware support, this only works with basic types (integers, and pointers).
Upvotes: 4
Reputation: 1243
It looks like the closest thing to the behavior I want is this:
std::atomic_store(
&b,
std::atomic_exchange(
&a,
b
)
);
However, this is not strictly atomic. a
and b
could point to the same address for a fraction of a second.
In my case, that behavior is acceptable as long as they both point to valid, well-defined objects at all times.
Upvotes: 0
Reputation: 62573
It has been puzzling me for ages why 'compare-and-swap' has swap
in it. It does not swap anything. It sets the value if check passess, and returns the current value if the check fails. So by no means atomic_exchange is any equivalent to std::swap.
Instead, it's a check-and-set pattern, so I always prefer CAS to mean compare-and-set.
Upvotes: 1