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商店与负载同步,但不是相反.
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火灾.