Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic usage of conditionals with std::atomic<T>

Tags:

c++

c++11

atomic

So I'm starting to familiarize myself with C++11 <atomic> types. In the past, when I had an atomic flag I would usually simply lock a mutex before accessing it. A common need would be to check if the flag is false, and if so, atomically set it to true and then do something. So basically this would be accomplished like this, where flag is a simple bool:

{
    std::lock_guard<std::mutex> lock(my_mutex);
    if (!flag) 
    {
        flag = true;
        // do something;
    }
}

So, now I'm trying to figure out how the same thing can be accomplished with <atomic>. The docs say that the assignment operator and operator T of an atomic type are atomic operations. However, if I change flag to std::atomic<bool>, I imagine I can't simple say:

if (!flag)
{
  flag = true;
  // do something
}

... because even though the expression (!flag) is atomic, and the assignment flag = true is atomic, there's nothing to prevent another thread from modifying flag in between those two statements.

So, if I understand correctly here, the only proper usage - at all - of conditionals with atomic types, where the result of the conditional could modify the atomic variable, is to use the Compare and Swap operation? Am I correct?

So, I'd have to say:

bool expected = false;
if (flag.compare_exchange_weak(expected, true))
{
   // do something
}

Am I correct in my understanding here?

like image 378
Siler Avatar asked Oct 30 '14 15:10

Siler


People also ask

What is std :: atomic in C++?

Each instantiation and full specialization of the std::atomic template defines an atomic type. Objects of atomic types are the only C++ objects that are free from data races; that is, if one thread writes to an atomic object while another thread reads from it, the behavior is well-defined.

Is shared_ptr Atomic?

std::shared_ptr requires special attention in a multithreading environment. They are very special. They are the only non-atomic data types in C+ for which atomic operations exist.

Is std :: swap Atomic?

It is not atomic. Atomic operations are not cheap and 99% of the time you do not need the atomicity. There are (IIRC) some other means to get atomic operations but std::swap() is not one of them.

Why is std atomic not movable?

std::atomic is not copyable or movable because its copy constructor is deleted and no move constructor is defined.


1 Answers

If you have multiple threads that are running the same code that need to do that flip, yes - you will need to use compare_exchange_weak() or compare_exchange_strong() for the precisely the reason you suggest (probably prefer strong).

However, it's not the case to say that this is the only proper usage of conditionals with atomics. If I have, say, one thread that only ever reads the atomic and one that writes to it, it's perfectly reasonable to use them the simple way... e.g.:

std::atomic<bool> done{false};

// thread 1
while (!done) {
    ....
}

// thread 2
stop() { done = true; }

There's no reason for me to do a done.compare_exchange_strong(expected, true) there. That's overkill. It's really on a case-by-case basis.

like image 167
Barry Avatar answered Sep 29 '22 12:09

Barry