Home > front end >  Is there a way to have a version of std::atomic's compare_exchange_strong method that exchanges
Is there a way to have a version of std::atomic's compare_exchange_strong method that exchanges

Time:12-22

I have an atomic type where I need to atomically compare it with a value, and if the two values are not equal then exchange the value of the atomic.

Put another way, where compare_exchange_strong essentially does this operation atomically:

if (atomic_value == expected)
    atomic_value = desired;

...I'm looking for a way to do this:

if (atomic_value != expected)
    atomic_value = desired;

(Yes, I know compare_exchange_strong compares using bitwise equality, not the == operator. And I know the value of expected gets assigned when the comparison fails. This was just for illustration purposes. In my use case I don't need the value of the atomic regardless of the result of the comparison.)

Is there any way to do this without having to fall back on using a lock instead of std::atomic?

CodePudding user response:

auto observed = atomic_value.load();
for (;;)
{
    if (observed == expected){
       break; // no exchange
    }
    if (atomic_value.compare_exchange_weak(observed, desired)) { 
       break; // successfully exchanged observed with desired
    }
}

Sure it is suboptimal on architectures where HW has LL/SC, as C does not expose it. With LL/SC can have arbitrary condition.

CodePudding user response:

Just use the loop one ordinarily uses with compare-and-exchange, but instead of looping until the (new) expected value matches, loop either until it matches (and the store happens) or it equals the value in your != expected condition, since that’s the case in which you needn’t do anything. (Obviously don’t make the initial value be that “unless” value so that you can’t “succeed” the first time.)

CodePudding user response:

You could use something like this:

#include <atomic>
#include <random>

std::atomic<int> atomVal;

int store_if_not_equal(int desired)
{
    while (true)    // or maxloop....
    {
        int expected = desired;

        if (atomVal.compare_exchange_strong(expected, desired))
        {
            // values matched - do nothing
            return 0;
        }
        else
        {
            //expected now contains the "current value"
            // another thread could have sneaked in and changed it,
            // so only replace it if it still matches
            if (atomVal.compare_exchange_strong(expected, desired))
            {
                // success
                return 1;
            }
        }

    // if we arrive here, retry
    }
}

int main()
{
    atomVal.store(rand());
    return store_if_not_equal(2);
}

Demo: https://godbolt.org/z/qWTP7canf

  • Related