Reputation:
https://timsong-cpp.github.io/cppwp/n4861/intro.races#8
An evaluation A is dependency-ordered before an evaluation B if (8.1) A performs a release operation on an atomic object M, and, in another thread, B performs a consume operation on M and reads the value written by A, or (8.2) for some evaluation X, A is dependency-ordered before X and X carries a dependency to B. [ Note: The relation “is dependency-ordered before” is analogous to “synchronizes with”, but uses release/consume in place of release/acquire. — end note ]
¿"Atomic object" is "something special" in C++ or is it just a name given to any variable in the context (when we talk about concurrency in c++) of concurrency in C++?
If it is something special, can you tell me what it is?
Upvotes: 1
Views: 180
Reputation: 67723
¿"Atomic object" is "something special" in C++ or is it just a name given to any variable in the context (when we talk about concurrency in c++) of concurrency in C++?
Literally 5 paragraphs above the one you quoted is
3 The library defines a number of atomic operations (atomics) ...
4 All modifications to a particular atomic object M ...
where the first mention of an atomic object comes immediately after the first reference to atomic operations, which links to the section describing only two new classes (well, class templates plus specializations): std::atomic
and std::atomic_ref
.
An atomic object is, in the broadest terms (edit for the avoidance of doubt, this means with more generality than C++ or any individual language), an object to which we can make atomic (meaning "indivisible") updates. So, another thread could read the old value, or the new value, but never a mixture of both.
That's not sufficient to actually do very much without:
All three of those things (indivisibility, explicit ordering and compiler control) are bundled together into the std::atomic
and std::atomic_ref
wrappers, with the necessary support from the C++ memory model.
Before this language support (the memory model plus the atomics library), the best we could do was write platform-specific code using intrinsics or assembler, or platform-specific libraries like pthreads.
Upvotes: 1
Reputation: 275385
Prior to a relatively recent version of C++, atomic objects are just std::atomic
stuff. It was simple. Now, it is more complex.
The introduction of atomic_ref
changed this:
[atomics.ref.generic] 31.7/1 reads:
An atomic_ref object applies atomic operations ([atomics.general]) to the object referenced by *ptr such that, for the lifetime ([basic.life]) of the atomic_ref object, the object referenced by *ptr is an atomic object ([intro.races]).
So atomic objects are std::atomic<T>
and family (std::atomic_bool
etc), plus anything wrapped by a std::atomic_ref<T>
. The std::atomic_ref<T>
is not atomic, but the wrapped thing becomes so.
The idea is that these atomic objects are the objects for which atomic operations (which are a special kind of thread-safe operations in the C++ standard) can apply to.
The fact that "normal" objects that are no longer wrapped in atomic_ref
are no longer atomic is important and tricky to think about. I suspect this rule exists because some platforms implement atomics using lock-based operations. On others, atomic operations can occur on most well-aligned memory.
std::atomic<int> a;
int b;
a
is atomic, b
is not.
{
std::atomic_ref<int> x(b);
now b
is an atomic object.
}
and now b
is not an atomic object.
Upvotes: 2
Reputation: 54589
In the simplest possible terms, an atomic object is an object of type std::atomic<T>
or std::atomic_ref<T>
.
These objects provide special operations for fine-grained atomic access to data that are subject to special guarantees from the language with regards to inter-thread synchronization, which form the basis of the C++ memory model.
See [intro.multithread] and [atomics.general] as the relevant sections in the latest draft standard.
Upvotes: 1