Many of the C++11 CAS operations (e.g., atomic_compare_exchange_weak
, atomic_compare_exchange_strong
) take two pointers and a value, i.e., like this:
bool atomic_compare_exchange(T* pointer, T* expected, // pseudodeclaration!
T desired);
In contrast, the CAS operations from Microsoft, gcc, and Intel all take one pointer and two values:
long InterlockedCompareExchange(long* pointer, long desired, // Microsoft
long expected);
int __sync_bool_compare_and_swap (T* pointer, T expected, // gcc and
T desired); // Intel
Why do the C++11 CAS functions take two pointers and a value instead of what appears to be a more conventional one pointer and two values?
The C++11 way is more useful: If the exchange fails, then *expected
is updated to the new, current value. That makes it easy to use the function in a loop:
T value = x.load();
T newvalue = frob(value);
while (!atomic_compare_exchange(&x, &value, newvalue))
{
newvalue = frob(value);
}
With the Microsoft signature, testing whether the operation succeeded is more cumbersome, and ditto for GCC's __sync_type
version. With GCC's __sync_bool
, you even need to perform another load each time the exchange fails.
I don't see why you wouldn't have both though. In my use-case the C++ version is less useful. I want to wait until a variable has some value then I want to set it to a new value.
With GCC instrinsics:
while (!__sync_bool_compare_and_swap(&value, expected, desired)) { }
With C++11:
auto tmp = expected;
while (!value.compare_exchange_weak(tmp,desired))
{
tmp = expected;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With