Question

You can safely increment and decrement std::atomic_int for example. But if you need to check for overflow or execute some routine conditinoally based on the value, then a lock is needed anyway. Since you must compare the value and the thread might be swapped off just after the comparison succeeded, another thread modifies, ... bug.

But if you need a lock then you can just use a plain integer instead of atomic. Am I right?

Was it helpful?

Solution

No, you can still use a std::atomic even conditionally.

Firstly, if you use std::atomic<unsigned int> then overflow behavoir is well defined (although possibly not what you want). If you use a signed integer overflow isn't well defined but as long as you don't hit it then this doesn't matter.

If you absolutely must check for overflow, or otherwise act conditionally, you can use compare-exchange. This lets you read the value, decide whether you want to do work on it and then atomically update the value back if it hasn't changed. And the key part here is the system will tell you if the atomic update failed, in which case you can go back to the start and read the new value and make the decision again.

As an example, if we only wanted to set the max value of an atomic integer to 4 (in some kind of refcounting, for instance), we could do:

#include <atomic>

static std::atomic<int> refcount = 0;

int val = refcount; // this doesn't need to be in the loop as on failure compare-exchange-strong updates it
while(true)
{
   if(val == 4)
   {
       // there's already 4 refs here, maybe come back later?
       break;
   }

   int toChangeTo = val + 1;
   if(refcount.compare_exchange_strong(val, toChangeTo))
   {
       // we successfully took a ref!
       break;
   }

    // if we fail here, another thread updated the value whilst we were running, just loop back and try again
}

In the above code you can use compare_exchange_weak instead. This can sometimes spuriously fail and so you need to do it in a loop. However, we have a loop anyway (and in general you always will as you need to handle real failures) and so compare_exchange_weak makes a lot of sense here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top