Reputation: 4730
I am reading the std::memory_order on the cppreference.com and the C++ 20 specification. I can't find the definition of the terms, "acquire operation" and "release operation".
The first document recursively defines the terms, saying "Atomic load with memory_order_acquire or stronger is an acquire operation." and "memory_order_acquire: A load operation with this memory order performs the acquire operation on the affected memory location."
And the second document seems to use the terms without any definition. It begins to use the terms, saying "A synchronization operation on one or more memory locations is either a consume operation, an acquire operation, a release operation, or both an acquire and release operation."
So I googled and found LINUX KERNEL MEMORY BARRIERS, which clearly defines the terms like the following.
(5) ACQUIRE operations.
This acts as a one-way permeable barrier. It guarantees that all memory operations after the ACQUIRE operation will appear to happen after the ACQUIRE operation with respect to the other components of the system. ACQUIRE operations include LOCK operations and both smp_load_acquire() and smp_cond_load_acquire() operations.
Memory operations that occur before an ACQUIRE operation may appear to happen after it completes.
An ACQUIRE operation should almost always be paired with a RELEASE operation.
Is this definition exactly the same thing what the authors meant for the term "acquire operation"?
Upvotes: 4
Views: 289
Reputation: 57922
I don't think of "acquire" as really having any meaning of its own. It's just a tag that the standard associates with a certain set of operations. Then the standard can describe properties of this set of operations by referring to them collectively as "acquire operations".
So in that sense, it doesn't require a definition.
This is sort of suggested by the first instance of the term in the standard, in [intro.races p2]:
The library defines a number of atomic operations (Clause 31) and operations on mutexes (Clause 32) that are specially identified as synchronization operations. These operations play a special role in making assignments in one thread visible to another. A synchronization operation on one or more memory locations is either a consume operation, an acquire operation, a release operation, or both an acquire and release operation.
So here "synchronization operation" is introduced as a more-or-less arbitrary tag that will be applied to certain types of operations. Then it is further subdivided into "consume", "acquire", and "release" which, in context, are also arbitrary tags.
If you really think that "acquire" needs a definition, then I would define it in either of the following ways:
Search the standard and make a list of all instances where an operation is stated to be an acquire operation. Then define "acquire operation" as "an operation appearing in that list".
Search the standard and make a list of all properties that acquire operations are stated to have. Then define "acquire operation" as "an operation having all the properties in that list".
To give an analogy that is somehow even more nerdy than sitting around parsing an ISO language standard: it's like asking where the term "thallid" is defined in the rules of Magic: The Gathering. Okay, in-universe it's some kind of fungus creature, but that's irrelevant to gameplay. All a player needs to know is that certain cards are marked as being thallids, and other cards may say that they interact with thallids in specific ways. So in that sense, the definition of "thallid" is, implicitly, "a card that has the words 'Summon Thallid' on it". (To be pedantic, "or any other entity, such as a token, that is stated to be a thallid"). And while this might seem to be circular, it really isn't.
Upvotes: 1
Reputation: 39424
The definition you have cited isn't recursive, it simply is a definition; however, it isn't properly formatted. The standard usually uses italic text to indicate when a term is defined, and I believe this should be applied here:
memory_order::acquire
,memory_order::acq_rel
, andmemory_order::seq_cst
: a load operation performs an acquire operation on the affected memory location.
All the properties of such an acquire operation (most importantly, release operations synchronize with it) are defined elsewhere, including in the next paragraph:
An atomic operation
A
that performs a release operation on an atomic objectM
synchronizes with an atomic operationB
that performs an acquire operation onM
and takes its value from any side effect in the release sequence headed byA
.
Synchronize with and its effects are defined in [intro.races].
In short, a load using std::memory_order::acquire
is an acquire operation, and this means that release operations synchronize with it. This synchronization is well-defined. Nothing is recursive; however, the formatting is misleading.
Note: this answer mostly relates to the C++ standard, but the same logic can be applied to the cppreference article as well.
Note: I've opened an an editorial issue about this in the C++ draft repository.
Upvotes: 7