C++ memory model: do seq_cst loads synchronize with seq_cst stores?

断了今生、忘了曾经 提交于 2019-12-06 04:44:45

问题


In the C++ memory model, there is a total order on all loads and stores of all sequentially consistent operations. I'm wondering how this interacts with operations that have other memory orderings that are sequenced before/after sequentially consistent loads.

For example, consider two threads:

std::atomic<int> a(0);
std::atomic<int> b(0);
std::atomic<int> c(0);

//////////////
// Thread T1
//////////////

// Signal that we've started running.
a.store(1, std::memory_order_relaxed);

// If T2's store to b occurs before our load below in the total
// order on sequentially consistent operations, set flag c.
if (b.load(std::memory_order_seq_cst) == 1) {
  c.store(1, std::memory_order_relaxed)
}


//////////////
// Thread T2
//////////////

// Blindly write to b.
b.store(1, std::memory_order_seq_cst)

// Has T1 set c? If so, then we know our store to b occurred before T1's load
// in the total order on sequentially consistent operations.
if (c.load(1, std::memory_order_relaxed)) {
  // But is this guaranteed to be visible yet?
  assert(a.load(1, std::memory_order_relaxed) == 1);
}

Is it guaranteed that the assertion in T2 cannot fire?

I'm looking for detailed citations of the standard here. In particular I think this this would require showing that the load from b in T1 synchronizes with the store to b in T2 in order to establish that the store to a inter-thread happens before the load from a, but as far as I can tell the standard says that memory_order_seq_cst stores synchronize with loads, but not the other way around.


回答1:


Do seq_cst loads synchronize with seq_cst stores?

They do if all necessary requirements are met; in your example code, the assert can fire

§29.3.3
There shall be a single total order S on all memory_order_seq_cst operations

This total order applies to the seq_cst operations themselves.. In isolation, a store(seq_cst) has release semantics, whereas a load(seq_cst) has acquire semantics.

§29.3.1-2 [atomics.order]
memory_order_release, memory_order_acq_rel, and memory_order_seq_cst:
a store operation performs a release operation on the affected memory location.
.....
§29.3.1-4 [atomics.order]
memory_order_acquire, memory_order_acq_rel, and memory_order_seq_cst:
a load operation performs an acquire operation on the affected memory location.

Therefore, atomic operations with non-seq_cst ordering (or non-atomic operations) are ordered with respect to seq_cst operations per the acquire/release ordering rules:

  • a store(seq_cst) operation cannot be reordered with any memory operation that is sequenced before it (i.e. comes earlier in program order)..
  • a load(seq_cst) operation cannot be reordered with any memory operation that is sequenced after it.

In your example, although c.store(relaxed) in T1 is ordered (inter-thread) after b.load(seq_cst) (the load is an acquire operation), c.load(relaxed) in T2 is unordered with respect to b.store(seq_cst) (which is a release operation, but it does not prevent the reordering).

You can also look at the operations on a. Since those are not ordered with respect to anything, a.load(relaxed) can return 0, causing the assert to fire.



来源:https://stackoverflow.com/questions/47520748/c-memory-model-do-seq-cst-loads-synchronize-with-seq-cst-stores

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!