问题1:我有一个主要用于计数的变量,只关心它自己的值。以下两种方法哪一种性能更好?
方法一: 读取:aaa.atomic_fetch_add(0, memory_order_relaxed) 写入:aaa.atomic_fetch_add(1, memory_order_relaxed)
方法2: 读取:aaa.load(memory_order_seq_cst) 写入:aaa.atomic_fetch_add(1, memory_order_seq_cst)
问题2:如果线程T1:aaa可能已经存在于T1的storebuffer中,T1的原子RMW操作会刷新storebuffer吗?
在 x86 上,
seq_cst
加载不需要额外的障碍,因此与 relaxed
加载一样便宜,除了编译时重新排序之外。纯负载比任何 RMW 都要快得多,例如在无争用情况下,每个时钟 3 个时钟与每 20 个时钟 1 个时钟,并且纯负载可通过多个并行读取器进行扩展。 (https://uops.info/ 看看 lock xadd
与 mov r32, mem
)
原子 RMW 是 x86 上的全面障碍;在 asm 中,没有办法让它们比
seq_cst
更弱。 (所以是的,他们必须等待存储缓冲区耗尽。)只有 .store(val, seq_cst)
需要任何额外的屏障指令(通常是 lock add byte [rsp], 0
,因为在许多 CPU 上它比 mfence
更快。)
就线程间延迟而言,两者应该表现相同; 存储缓冲区已经尝试尽快耗尽自身以避免变满和停滞。 (当从前端向后端发出存储 uop 时,前端必须分配一个存储缓冲区条目,因此不这样做对于乱序 exec 能看到的距离来说会更糟。)请参阅除了提供必要的保证之外,硬件内存屏障是否还能使原子操作的可见性更快?(否)