I would like to summarize the relevant rules for Rust, to see if I understand them correctly now.
I'll start with which parts here are relevant and which are not for Rust:
I will only care about the "formal description" here.
Sequenced-before
This is a relationship that only makes sense to look at in one thread (and not across thread boundaries), and it's determined according to the evaluation order.
E.g. when I write:
*a = 1;
*b = 2;
Then *a = 1
is sequenced-before *b = 1
.
Carries dependency
Irrelevant to Rust as Rust doesn't support the Consume
ordering.
Modification order
This applies to each single atomic variable and describes in which order the variable is changed to which value. When looking at one particular atomic variable, the order is a total order that is equal for all threads.
However, I cannot determine a modification order involving two different atomic variables. It only applies to one atomic variable each.
Release sequence
The relevant part from the C++ reference is this:
After a release operation A is performed on an atomic object M, the longest continuous subsequence of the modification order of M that consists of
Writes performed by the same thread that performed A (until C++20)
- Atomic read-modify-write operations made to M by any thread
is known as release sequence headed by A.
Basically it means that if I do a release operation on an atomic M which is followed by several read-modify-write operations (such as fetch_add
for example), then these read-modify-write operations belong to the release sequence (until some other modification (i.e. write) operation happens (such as a plain store
).
Dependency-ordered before
Again, irrelevant for Rust as of now due to lack of Consume
ordering.
Inter-thread happens-before
This is a relation of operations running on different threads. Relevant here is:
Between threads, evaluation A inter-thread happens before evaluation B if any of the following is true
- A synchronizes-with B
A is dependency-ordered before B (irrelevant for Rust)
- A synchronizes-with some evaluation X, and X is sequenced-before B
- A is sequenced-before some evaluation X, and X inter-thread happens-before B
- A inter-thread happens-before some evaluation X, and X inter-thread happens-before B
The subset of happens-before (see below) which looks at two operations A and B which are on different threads.
Happens-before
I would say this is the transitive closure of sequenced-before (on same thread) and synchronizes-with (on different threads) relationships.
Where two operations A and B are on the same thread, we can also speak of sequenced-before, and where A and B are on a different thread, we can also speak of inter-thread happens-before.
Happens-before is the union of both sequenced-before and inter-thread happens-before.
Simply happens-befoere
Irrelevant for Rust as it will be the same as happens-before due to lack of Consume
ordering.
Strongly happens-before
Same as happens-before but includes the SeqCst
case:
- A synchronizes with B, and both A and B are sequentially consistent atomic operations
And the elements required to form the transitive closure:
- A strongly happens-before X, and X strongly happens-before B
Synchronizes with
This basically means an Acquire
operation read a value from a previous Release
operation or an operation in the release sequence, i.e. the release operation or any contiguously following read-modify-write operations in the modification order.
Edit: The operation that heads the release sequence, i.e. the initial Release
operation then synchronizes-with the Acquire
operation.
Not sure if this summary is correct. Maybe I wasn't very precise, but I feel like I have a basic understanding now on what's going on and how these things work.
I find the documentation very difficult to read though, mostly because the synchronizes-with isn't explained at all in the C++ std::memory_order
reference (only in the standard or one of its drafts), and because the C++ reference is also including things which are not relevant for Rust and make things harder to understand.
Perhaps someone can give me feedback if my reasoning regarding the transitive closure is correct.