I want to compare and exchange 3 atomic variable:
std::atomic<int> a;
std::atomic<int> expected;
std::atomic<int> new;
int expectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
int newValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);
std::atomic_compare_exchange_strong_explicit(
&a,
&expectedValue,
newValue,
std::memory_order_relaxed,
std::memory_order_relaxed);
But if in between reading expected
and new
variables and comparing them to a
, one another thread change theirs values, current thread will work by previous values, so i change code to it:
while(true)
{
int expectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
int newValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);
std::atomic_compare_exchange_strong_explicit(
&a,
&expectedValue,
newValue,
std::memory_order_relaxed,
std::memory_order_relaxed);
int newExpectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
int newNewValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);
if(newExpectedValue == expectedValue && newNewValue == newValue)
break;
}
Is my code correct? or is there a better way to do this?
Why are
expected
andnew
atomic in the first place? Typically, you compute the new value somehow on some thread, and only that thread knows the new value, and does the compare_exchange. Similarly, the value ofexpected
is the old value before that thread started it's computation - but that expected, old value is again only important for that one thread.In short:
expected
andnew
should not be shared across threads.Your rewritten function can still give inconsistent results. What if
expected
changes after you load it intonewExpectedValue
, but before you check ifnewExpectedValue == expectedValue
? What ifnew
andexpected
change after you loadexpected
, but beforenew
?This isn't how atomics are intended to be used. If you need to do an operation involving three variables atomically, you should be using a lock to serialize access during the operation. A mutex or spin lock would be more appropriate here.