2

Say I have atomic<int> i; Thread A performs an atomic store/exchange with memory_order_release. Next, Thread B performs an atomic store with memory_order_release. Thread C performs an atomic fetch_add(0, memory_order_acquire);

Does Thread C acquire dependencies from thread A and B or only thread B?

T.C.
  • 133,968
  • 17
  • 288
  • 421
rnpl
  • 87
  • 9
  • 1
    Your use of the word 'next' is not very useful. Since B performs a plain store, it does not (have to) update the latest in the modification order and as long as the store by B has not been committed to L1 cache (ie. it's still in the store buffer), C won't see it even though it is "next".. More detail should be added – LWimsey May 28 '18 at 22:15

2 Answers2

5

Only B (I'm going to assume that by "next" you mean the modification order of the atomic is A -> B -> C so that by [atomics.order]p11 C's RMW must read the value B wrote). See the note in [intro.races]p6:

Except in the specified cases, reading a later value does not necessarily ensure visibility as described below. Such a requirement would sometimes interfere with efficient implementation.

The read part of the fetch_add is an acquire operation that took its value from the store-release, so the store release synchronizes with the RMW by [atomics.order]p2:

An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.

However, the store/release performed by thread B is not an RMW operation and therefore is not part of the release sequence headed by thread A's store (see [intro.races]p5). Therefore, thread A's store doesn't synchronize with the fetch_add.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Note that the OP has since removed the word "next" and replaced it with "happens after". So the reasoning here may not be correct based on the new language since we have that A happens before B. Of course, the user did explain how exactly the happens before relationship is established between A and B is established (because just the store can't do it), but if we take it at face value (e.g., perhaps there is a load on the thread B that synchronizes with the release store in A, before the store B) then probably C happens before A and B. – BeeOnRope May 28 '18 at 23:54
  • Sure, "happens before" is transitive in the absence of consume. But 1) I don't care about post-answer changes to the question that invalidates the answer and 2) the modified version is borderline meaningless, since the whole thing is about whether you can establish a "happens before". – T.C. May 28 '18 at 23:59
  • 1
    Sure, but that note is not only for you, but also for other users who'll now see an accepted answer which combined with the current question text seems to contradict the transitivity of happens-before. At least for users who don't carefully check the edit diffs and compare with the timestamp of your answer. I agree the update made things messy. – BeeOnRope May 29 '18 at 00:01
0

edit: see answer of T.C.

this leaves only this part of my answer:

i'd strongly recommend to use atomics with their default memory order (memory_order_seq_cst) unless you have a really good reason (measure performance) to do otherwise.

skeller
  • 1,151
  • 6
  • 6
  • 1
    In the uncontended case, `release` is *very* cheap on x86, much cheaper than x86's `seq_cst` (a full memory barrier hurts the pipeline a lot, and compilers these days often use `mov [shared],reg` / `mfence` [which blocks out-of-order execution on recent Intel CPUs](https://stackoverflow.com/questions/50494658/are-loads/50496379#50496379), unlike `xchg`). In x86 machine code, every store is a release-store, so the hardware is excellent at it. Especially if you have a variable that's written often and only read occasionally, `mo_release` is definitely worth considering. – Peter Cordes May 28 '18 at 22:00
  • @Peter Cordes i fully agree, but if you read/write the atomic not very often, this optimization is not necessary and a later maintainer will have it a bit easier – skeller May 29 '18 at 15:47