I have a struct in a union with uint64_t, providing access to two int32_t. I would like to decrement one of the struct members atomically. I came up with this:
class{
public:
void atomicallyDecrement_B(const int32_t decrementByThisValue){
MyUnion newUnion;
MyStruct currentStruct = _union._data;
do{
const int32_t currentB = currentStruct.b;
const int32_t currentA = currentStruct.a;
const int32_t newB = currentB - decrementByThisValue;
newUnion._data.a = currentA;
newUnion._data.b = newB;
}
while(!std::atomic_compare_exchange_weak(&_union._data, ¤tStruct, newUnion._data));
}
private:
struct MyStruct{
int a;
int b;
};
union MyUnion{
MyUnion(){
_data.a = 0;
_data.b = 0;
}
MyStruct _data;
uint64_t _atomic;
} _union;
};
but it seems the first argument to atomic_compare_exchange_weak()
must be an atomic type itself. Is there any way to perform this operation without changing the uint64_t data member to be std::atomic<uint64_t>
?
I am using GCC 5.2
GCC has atomic operations as built-ins. They are described on this page.
The operation you are looking for is
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
or
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
These builtins perform an atomic compare and swap. That is, if the current value of *ptr is oldval, then write newval into *ptr.
For Windows users the corresponding capability is
LONG __cdecl InterlockedCompareExchange(
_Inout_ LONG volatile *Destination,
_In_ LONG Exchange,
_In_ LONG Comparand
);
Which is described here
Example using the bool form of the gcc intrinsic:
do{
int oldVal = protectedVal;
int newVal = someFunction(oldVal);
} while (__sync_bool_compare_and_swap(&protectedVal, oldVal, newVal);