C++内存模型:seq_cst加载与seq_cst存储同步吗?

jac*_*bsa 4 c++ atomic memory-model language-lawyer stdatomic

在C++内存模型中,所有顺序一致操作的所有加载和存储都有一个总顺序.我想知道这是如何与具有其他内存排序的操作交互,这些内存排序在顺序一致的加载之前/之后排序.

例如,考虑两个线程:

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);
}
Run Code Online (Sandbox Code Playgroud)

是否保证T2中的断言无法触发?

我在这里寻找标准的详细引用.特别是我认为这需要显示bT1 中的负载b T2中的存储同步,以便确定存储到a线程之间的情况发生在加载之前a,但据我所知,标准说memory_order_seq_cst商店与负载同步,但不是相反.

LWi*_*sey 6

seq_cst加载与seq_cst商店同步吗?

如果满足所有必要的要求,他们会这样做 在您的示例代码中,assert可以触发

§29.3.3
在所有memory_order_seq_cst操作中应该有一个总订单S.

这个总顺序适用于seq_cst操作本身.在隔离中,a store(seq_cst)具有释放语义,而a load(seq_cst)具有获取语义.

§29.3.1-2[atomics.order]
memory_order_release,memory_order_acq_rel和memory_order_seq_cst:
存储操作对受影响的内存位置执行释放操作.
.....
§29.3.1-4[atomics.order]
memory_order_acquire,memory_order_acq_rel和memory_order_seq_cst:
加载操作对受影响的内存位置执行获取操作.

因此,seq_cst对于seq_cst按照获取/释放排序规则的操作,对非排序(或非原子操作)的原子操作进行排序:

  • 一个store(seq_cst)操作不能与被它之前(即,在程序顺序较早谈到)测序任何存储器操作被重新排序..
  • 一个load(seq_cst)操作不能用它之后被测序的任何存储操作重新排序.

在你的榜样,虽然c.store(relaxed)T1之后排序(线程间)b.load(seq_cst)(该load是获取操作), c.load(relaxed)T2是无序相对于b.store(seq_cst)(这是一个释放操作,但它并不妨碍重新排序).

您还可以查看操作a.由于那些没有任何订单,a.load(relaxed)可以返回0,导致assert火灾.