There is a thread discussing the definition of atomic object. The most popular interpretations are the followings:
- By an "atomic object" we understand an object whose public interface exposes only atomic operations, i.e. all operations you can do with that object are atomic.
- The C++ has the standard
std::atomic<T>class template which fits the above descriptions. - The C++ standard imposes a set of rules on operations and effects of operations on atomic objects ([intro.races]). If all operations on an object satisfy those rules, then that object is atomic.
I see two possible interpretations for the atomic object:
- An
std::atomic<T>typed object - An underlying
Ttyped object managed by anstd::atomic<T>typed object
Based on the comments and in my understanding "atomic object" should refer an object with std::atomic<T> type - so the first interpretation is the correct one -, but it has serious consequences, like in the following context:
C++20 standard 6.9.2.1 (15):
If an operation
Athat modifies an atomic objectMhappens before an operationBthat modifiesM, thenAshall be earlier thanBin the modification order ofM.
There is an std::atomic operation with the following footprint:
void notify_one() noexcept;
As it is not a const function it modifies the std::atomic object, but it doesn't modify the underlying T object. Does notify_one modify the atomic object M? (Does M refer the std::atomic<T> typed object, or its underlying T object?). If it does refer the std::atomic typed object then C++20 standard 6.9.2.1 (15) can be applied for the notify_one operations.
It is crucial to know to be able to answer questions like C++20: How is the returning from atomic::wait() guaranteed by the standard?.
The standard is confusing however, e.g. here, it weakens my reasoning and says atomic object is the managed object (at least in the case of atomic_ref):
An
atomic_refobject applies atomic operations ([atomics.general]) to the object referenced by*ptrsuch that, for the lifetime ([basic.life]) of theatomic_refobject, the object referenced by*ptris an atomic object ([intro.races]).
UPDATE
How could this interpretation affect wait/notify (C++20: How is the returning from atomic::wait() guaranteed by the standard?)? Let's suppose notify modifies the atomic object. That modification would be simply an indication that a wait should be woken up - and nothing to do with the current value managed by the atomic (so basically a futex wake that modifies the object, stores a flag, or whatever). As both store and notify are operations
that modifies an atomic object
M, thenAshall be earlier thanBin the modification order ofM
and
this effectively makes the cache coherence guarantee provided by most hardware available to C++ atomic operations.
So whenever notify is called after a store, the effect of that store operation is guaranteed to be observable on each and every waiting thread when that thread observes notify (as notify is later than store in the total order). If there is a waiting operation "M is eligible to be unblocked by a call to an atomic notifying operation" then notify must unblock it, and the value set by store has to be observable by the unblocked wait as an implication of 6.9.2.1 (15):
If an operation
Athat modifies an atomic objectMhappens before an operationBthat modifiesM, thenAshall be earlier thanBin the modification order ofM.
and 6.9.2.1 (4):
All modifications to a particular atomic object
Moccur in some particular total order, called the modification order ofM.