I am reading the C++ memory model defined in n3485 and it talks about release/acquire semantics, which from what I understand, and also from the definitions given in this blog:
Acquire semantics is a property which can only apply to operations which read from shared memory, whether they are read-modify-write operations or plain loads. The operation is then considered a read-acquire. Acquire semantics prevent memory reordering of the read-acquire with any read or write operation which follows it in program order.
Release semantics is a property which can only apply to operations which write to shared memory, whether they are read-modify-write operations or plain stores. The operation is then considered a write-release. Release semantics prevent memory reordering of the write-release with any read or write operation which precedes it in program order.
is going to prevent reordering of reads/writes before or after the current read/write being done. The first (acquire) will make sure that the read currently being done is not reordered with any read/write coming after it, the latter (release) will make sure that the current write is not being reordered with read/write operations that come before it.
Now can it be said that std::mutex::lock
will have acquire semantics and that std::mutex::unlock
essentially has release semantics?
In the Standard I can find this under section
30.4.1.2 Mutex types [thread.mutex.requirements.mutex]
11 Synchronization: Prior
unlock()
operations on the same object shall synchronize with (1.10) this operation.
From what I understand synchronize with is not explicitly defined in the standard, however it seems to be a type of happens before relation looking at two statements being evaluated between two different threads, however, from my understanding of acquire/release semantics, this has more to do with memory reordering. synchronize with could also be called release/acquire semantics?
So do release/acquire semantics apply not only to reordering of load/store operations and also intra-thread interleaving of operations?
In the standard section about the memory-model it mostly talks about ordered relations in terms of two threads interleaving. This leaves open to interpretation as to whether this applies also to memory ordering.
Can anybody clarify?
Now can it be said that std::mutex::lock will have acquire semantics and that std::mutex::unlock essentially has release semantics?
Yes, this is correct.
From what I understand synchronize with is not explicitly defined in the standard
Well, in theory Paragraph 1.10/8 is probably meant to give the definition of synchronizes with:
Certain library calls synchronize with other library calls performed by another thread. For example, an atomic store-release synchronizes with a load-acquire that takes its value from the store (29.3). [Note: ...]
On the other hand, this does not sound like a very formal definition. However, a better, though implicit one is indirectly given in Paragraph 1.10/10:
An evaluation A is dependency-ordered before an evaluation B if
— A performs a release operation on an atomic object M, and, in another thread, B performs a consume operation on M and reads a value written by any side effect in the release sequence headed by A, or
— 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 ]
Since the "is analogous to" relationship is most often symmetric, I would say that the above definition of "is-dependency-ordered before" indirectly provides a definition of "synchronizes with" as well - although you might correctly object that notes are non-normative; still, this seems to be the intended definition.
My intuition of the synchronizes with relationship is that it occurs between a write (atomic) operation performed by one thread that stores a certain value and the first (atomic) operation that reads that value. That operation might as well be in the same thread.
If the two operations are on different threads, then the synchronizes-with relation establishes a cross-thread ordering on operations.
In the Standard I can find this under section
30.4.1.2 Mutex types [thread.mutex.requirements.mutex]
11 Synchronization: Prior
unlock()
operations on the same object shall synchronize with (1.10) this operation.
To me, this seems compatible with the interpretation given above. An operation with release semantics (unlock, store) will synchronize with an operation of acquire semantics (lock, load).
however, from my understanding of acquire/release semantics, this has more to do with memory reordering. synchronize with could also be called release/acquire semantics?
Release and acquire semantics describe the nature of some operations; the synchronizes-with relationship is (indeed) a relationship which is established between operations that have acquire or release semantics, in a well-defined way.
So in a sense, synchronizes-with is a consequence of the semantics of those operations, and we use those semantics to achieve the correct ordering of instructions and constraint the possible reordering that the CPU or the compiler will perform.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With