0

I'm reading the cpp reference manual on std::atomic (https://en.cppreference.com/w/cpp/atomic/atomic) and I'm confused about the exact operations that are actually executed atomically.

The main operations I'm having trouble with:
operator=, operator+, and operator+=
I know that these operations are defined for the template I'm just unsure if and when they actually are atomic. I'd appreciate help understanding when an operation on such a variable is atomic and not.

Edit:
I've read the question referenced here: What exactly is std::atomic? and I'm still confused. For example, say a is an atomic int. Is a+=100 equivalent to a.fetch_add(100)?
In the same line of questioning, is a.load(100) equivalent to a=100?

EliT
  • 27
  • 8
  • 3
    If you click on the link on the page you linked to in the question to go to the operators page it will tell you. Eg: https://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2 – NathanOliver Jun 02 '19 at 16:22
  • @NathanOliver It doesn't say outright which of the operations are atomic and which aren't – EliT Jun 02 '19 at 16:24
  • 2
    Possible duplicate of [What exactly is std::atomic?](https://stackoverflow.com/questions/31978324/what-exactly-is-stdatomic) – Jelle Bleeker Jun 02 '19 at 16:25
  • 1
    All the operators implemented by the atomic (as defined in the standard) are atomic. If an operator is not implemented it is not atomic (you will not be able to use undefined operators anyway) – indeterminately sequenced Jun 02 '19 at 16:35
  • 5
    The very first sentence is *Atomically replaces the current value with the result of computation involving the previous value and arg. The operation is read-modify-write operation.*. How much more outright do you want? – NathanOliver Jun 02 '19 at 18:33
  • This is a very good talk where he lists the operators clearer than I can: https://www.youtube.com/watch?v=ZQFzMfHIxng – Treebeard Jun 03 '19 at 16:16

2 Answers2

0

After watching @Treebeard's link https://www.youtube.com/watch?v=ZQFzMfHIxng (watch minutes 13-15 for the relevant information)
Any operation performed on an atomic variable is atomic. However, the same line can contain more than one operation in it.
So for example given the following code:

std::atomic<int> a = 1;  
std::atomic<int> b = 1;   
auto c = std::atomic<int>(0);  
c = a + b;  

the last line is not an atomic operation, as a+b is in itself atomic, operator= is in itself atomic. However together they constitute 2 operations, which together are not atomic. To conclude, I'd recommend using the template's explicit functions such as load(), fetch_add(), and store(), instead of using standard overloaded operators, as these can be guaranteed to be executed atomically.

EliT
  • 27
  • 8
  • 2
    `a+b` isn't atomic; those are plain `int` variables so reading them has no guarantees of anything. They produce a value that is atomically stored into `c`, though. (With the default `memory_order_seq_cst`) – Peter Cordes Jun 04 '19 at 20:51
  • @PeterCordes On the other hand, they are probably meant in the same block so I don't see how could other thread change them (maybe it can, I don't know), but I think the example was a simplification, maybe bad example. – Lukas Salich Apr 09 '20 at 11:12
  • 1
    @LukasSalich: This answer says *as a+b is in itself atomic*. That's nonsense, a total distortion of whatever point this example might have been trying to make. The overall point that the whole C++ statement is not one atomic transaction is correct, though. – Peter Cordes Apr 09 '20 at 11:22
  • after edit that changed from `int a,b;` to `std::atomic a,b`: It's still wrong to say that the addition itself in `a + b` is atomic. It's still operating on two `int` objects, using the overloaded `(T)` cast operator of std::atomic. This is now `a.load() + b.load()`, doing separate two atomic loads, adding the temporary results, and doing an atomic store. This is **three separate atomic operations, not two**. You're *not* reading `a` and `b` at the same time, instead reading them in some order. – Peter Cordes Sep 20 '21 at 14:21
  • C++ doesn't have a way to make a larger atomic transaction, except to group vars into on `struct` and do `compare_exchange_weak` retry loops on a whole `atomic`. But if it's larger than 2 pointers on most systems, even that won't be lock-free. (And x86-64 doesn't have cheap atomic 16-byte loads.) – Peter Cordes Sep 20 '21 at 14:25
-1

If the standard specifies that an operation is atomic (which it does for everything on a std::atomic<T> except the constructor), then it is. It is up to the implementation to make sure that the promise made by the standard is upheld. If the implementation does not uphold the promise, then you have a non-conforming implementation on your hands.

Each operation on an atomic variable is separately atomic, i.e. each call of a std::atomic (member) function, via overload or explicitly. Multiple calls don't compose into an atomic transaction even if you do more than one in a single statement or expression.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70