Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do C++11 CAS operations take two pointer parameters?

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?

like image 425
KnowItAllWannabe Avatar asked Apr 16 '13 17:04

KnowItAllWannabe


2 Answers

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.

like image 89
Kerrek SB Avatar answered Oct 19 '22 23:10

Kerrek SB


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;
}
like image 42
modelm Avatar answered Oct 19 '22 22:10

modelm