59

I wasn't aware of the std::atomic variables but was aware about the std::mutex (weird right!) provided by the standard; however one thing caught my eye: there are two seemingly-same (to me) atomic types provided by the standard, listed below:

  1. std::atomic<bool>

  2. std::atomic_flag

The std::atomic_flag contains the following explanation:

std::atomic_flag is an atomic boolean type. Unlike all specializations of std::atomic, it is guaranteed to be lock-free. Unlike std::atomic<bool>, std::atomic_flag does not provide load or store operations.

which I fail to understand. Is std::atomic<bool> not guaranteed to be lock-free? Then it's not atomic or what?

So what's the difference between the two and when should I use which?

Konrad Rudolph
  • 482,603
  • 120
  • 884
  • 1,141
hg_git
  • 2,234
  • 5
  • 20
  • 42
  • 6
    "Atomic" and "lock-free" aren't synonyms. You can easily be lock-free without being atomic (that's what happens when you don't do any synchronization, for example :P), and you can easily have an atomic operation that isn't lock-free (for example, using a monitor). – Luaan Sep 05 '16 at 12:52

2 Answers2

43

std::atomic bool type not guranteed to be lock-free?

Correct. std::atomic may be implemented using locks.

then it's not atomic or what?

std::atomic is atomic whether it has been implemented using locks, or without. std::atomic_flag is guaranteed to be implemented without using locks.

So what's the difference b/w two

The primary difference besides the lock-free guarantee is:

std::atomic_flag does not provide load or store operations.


and when should I use which?

Usually, you will want to use std::atomic<bool> when you need an atomic boolean variable. std::atomic_flag is a low level structure that can be used to implement custom atomic structures.

eerorika
  • 181,943
  • 10
  • 144
  • 256
  • 3
    If the target architecture supports atomic operations, there would be no reason to use locks. But if it doesn't, I wonder *how* would `std::atomic_flag` be implemented then? – rustyx Sep 05 '16 at 11:23
  • [for edit] yes because load and store might not be relevant with boolean `std::atomic` but will be with other types. – hg_git Sep 05 '16 at 11:28
  • 9
    @RustyX: all existing architectures support at least atomic load-and-set-word (or equivalent negated load-and-clear-word), which is enough to implement `std::atomic_flag`, but not much more. See PA-RISC, where `ldcw` is the only atomic RMW op. –  Sep 05 '16 at 11:30
  • 1
    @RustyX: Hypothetically, it couldn't, and that would be the end of it. But as Fanael says that's not a problem in reality. – Lightness Races in Orbit Sep 05 '16 at 11:31
  • And for `std::atomic` you need CAS I guess... clear, thanks! – rustyx Sep 05 '16 at 11:36
  • 3
    @RustyX Actually, you don't need hardware support to provide lock-free atomicity - there are algorithms that can do this safely. However, one of the main reasons to use lock-free code in the first place is to improve performance over heavily contented data/code - and those algorithms are much slower than a lock. `std::atomic` does that choice for you based on the architecture you're compiling for. `std::atomic_flag` is "I totally, absolutely need lock-free, no matter how much it costs". – Luaan Sep 05 '16 at 12:55
  • 4
    @Luaan: You need lock-free atomics for signal-handling, because you cannot use a lock to protect state shared with a signal-handler without risking self-deadlock. – EOF Sep 05 '16 at 23:56
  • @EOF: These lock-free operations however, only need to be asynchronous-signal safe and not thread-safe (assuming there are multiple hardware threads). That said, you would typically use thread-safe atomic operations to implement a lock in the first place, so any hardware that supports multiple hardware threads but no thread-safe atomic operations like test and set is most certainly brain-damaged. – Arne Vogel Aug 17 '17 at 14:02
  • @ArneVogel state shared between signal handlers and normal execution only needs to be `volatile sig_atomic_t` **iff** only one thread is accessing the state, and that thread is also the only thread that can be signaled. Otherwise, you certainly need thread-safe atomics for shared mutable state accessed in signal handler context. – EOF Aug 17 '17 at 17:22
28

std::atomic<T> guarantees that accesses to the variable will be atomic. It however does not says how is the atomicity achieved. It can be using lock-free variable, or using a lock. The actual implementation depends on your target architecture and the type T.

std::atomic_flag on the other hand is guaranteed to be implemented using a lock-free technique.

michalsrb
  • 4,202
  • 13
  • 29