Template:cpp/atomic/sequentially-consistent
被标为 memory_order_seq_cst 的原子操作不仅以与释放-获得定序相同的方式进行内存定序(在一个线程中先发生于存储的任何副作用都变成进行加载的线程中的可见副作用),还对所有带此标签的内存操作建立了一个单独全序。
| 正式而言,
对原子对象 M 进行加载的每个
若存在
设有 M 上的一对原子操作,称之为 A 和 B,这里 A 写入、B 读取 M 的值,若存在二个
设有 M 上的一对原子操作,称之为 A 和 B,若符合下列条件之一,则 M 的修改顺序中 B 先发生于 A:
注意这表明: 1) 一旦出现未标记
memory_order_seq_cst 的原子操作,则立即丧失序列一致性,2) 序列一致栅栏仅为栅栏自身建立全序,而不为通常情况下的原子操作建立(先序于 不是跨线程关系,不同于先发生于) |
(C++20 前) |
| 正式而言,
某原子对象 M 上的原子操作连贯先序于 M 上的另一原子操作 B,若下列任一为真: 1) A 是修改,而 B 读取 A 所存储的值,
2) A 在 M 的修改顺序中前于 B,
3) A 读取原子操作 X 所存储的值,而 X 在修改顺序中前于 B,且 A 与 B 不是同一读修改写操作,
4) A 连贯先序于 X,而 X 连贯先序于 B。
所有 1) 若 A 与 B 为
memory_order_seq_cst 操作,而 A 强先发生于 B,则 A 在 S 中前于 B,2) 对于对象 M 上的每对原子操作 A 与 B,其中 A 连贯先序于 B:
a) 若 A 与 B 都是
memory_order_seq_cst 操作,则 S 中 A 前于 B,b) 若 A 是
memory_order_seq_cst 操作,而 B 先发生于 memory_order_seq_cst 栅栏 Y,则 S 中 A 前于 Y,c) 若
memory_order_seq_cst 栅栏 X 先发生于 A,而 B 为 memory_order_seq_cst 操作,则 S 中 X 前于 B,d) 若
memory_order_seq_cst 栅栏 X 先发生于 A,而 B 先发生于 memory_order_seq_cst 栅栏 Y,则 S 中 X 前于 Y。正式定义确保: 1) 单独全序与任何原子对象的修改顺序一致。
2)
memory_order_seq_cst 加载到的值,要么来自最后一次 memory_order_seq_cst 修改,要么来自某个不先发生于顺序中之前的 memory_order_seq_cst 修改操作的非 memory_order_seq_cst 修改。单独全序可能与先发生于不一致。这允许 例如,对于初值为零的 // 线程 1 :
x.store(1, std::memory_order_seq_cst); // A
y.store(1, std::memory_order_release); // B
// 线程 2 :
r1 = y.fetch_add(1, std::memory_order_seq_cst); // C
r2 = y.load(std::memory_order_relaxed); // D
// 线程 3 :
y.store(3, std::memory_order_seq_cst); // E
r3 = x.load(std::memory_order_seq_cst); // F
允许这些操作产生 注意: 1) 一旦出现未标记
memory_order_seq_cst 的原子操作,程序的序列一致保证就会立即丧失,2) 多数情况下, memory_order_seq_cst 原子操作相对于同一线程所进行的其他原子操作可重排。 |
(C++20 起) |
在多生产者-多消费者的情形中,若所有消费者都必须以相同顺序观察到所有生产者的动作出现,则可能必须进行序列定序。
全序列定序在所有多核系统上都要求完全的内存栅栏 CPU 指令。这可能成为性能瓶颈,因为它强制受影响的内存访问传播到每个核心。