Yve*_*ves 4 c++ performance atomic memory-barriers stdatomic
在问了这个问题之后,我了解到原子指令,例如test-and-set
,不会涉及内核。只有当进程需要进入睡眠状态(等待获取锁)或唤醒(因为它无法获取锁但现在可以)时,内核才必须参与执行调度操作。
如果是这样,是否意味着内存栅栏(例如std::atomic_thread_fence
在 c++11 中)不会也涉及内核?
在几乎所有普通 CPU(我们在现实生活中编程的那种)上,内存屏障指令都是无特权的,并且直接由编译器使用。 用同样的方法编译器知道如何发出像x86指令lock add [rdi], eax
的fetch_add
(或者lock xadd
,如果您使用的返回值)。或者在其他 ISA 上,它们在加载、存储和 RMW 之前/之后使用相同的屏障指令来提供所需的排序。 https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/
在一些任意假设的硬件和/或编译器上,当然任何事情都是可能的,即使这对性能来说会是灾难性的。
在 asm 中,屏障只是让这个内核等待,直到其他内核可以看到某些先前的(程序顺序)操作。 这是一个纯粹的本地操作。(至少,这就是真实 CPU 的设计方式,因此顺序一致性是可恢复的,只有本地障碍来控制加载和/或存储操作的本地排序。所有内核共享缓存的一致视图,通过类似的协议进行维护MESI。存在非一致性共享内存系统,但实现不会跨它们运行 C++ std::thread,并且它们通常不运行单系统映像内核。)
脚注 1:(即使是非无锁原子通常也使用轻量级锁定)。
此外,ARMv7 之前的 ARM 显然没有适当的内存屏障指令。在 ARMv6 上,GCCmcr p15, 0, r0, c7, c10, 5
用作屏障。
在此之前(g++ -march=armv5
和更早),GCC 不知道该做什么并调用__sync_synchronize
(一个 libatomic GCC 辅助函数),希望以某种方式为代码实际运行的任何机器实现。这可能涉及对假设的 ARMv5 多核系统的系统调用,但更有可能的是二进制文件将在 ARMv7 或 v8 系统上运行,其中库函数可以运行dmb ish
. 或者,如果它是一个单核系统,那么我认为它可能是一个空操作。(C++ 内存排序关心其他 C++ 线程,而不是可能的硬件设备/DMA 所看到的内存顺序。通常实现假设一个多核系统,但这个库函数可能是一个可以使用单核实现的情况.)
例如,在 x86 上,std::atomic_thread_fence(std::memory_order_seq_cst)
编译为mfence
. 较弱的障碍,比如std::atomic_thread_fence(std::memory_order_release)
只需要阻止编译时重新排序;x86 的运行时硬件内存模型已经是 acq/rel (seq-cst + a store buffer)。所以没有任何对应于barrier的asm指令。(C++ 库的一种可能实现是 GNU C asm("" ::: "memory");
,但 GCC/clang 确实有屏障内置。)
std::atomic_signal_fence
只需要阻止编译时重新排序,即使在弱排序的 ISA 上也是如此,因为所有现实世界的 ISA 都保证单个线程内的执行将其自己的操作视为按程序顺序发生。(硬件通过让负载监听当前内核的存储缓冲区来实现这一点)。VLIW 和 IA-64 EPIC,或其他显式并行 ISA 机制(如 Mill 及其延迟可见性负载),仍然使编译器能够生成遵守任何 C++ 排序保证的代码,如果异步信号(或内核代码中断)在任何指令之后到达。
您可以在Godbolt 编译器资源管理器上自己查看代码生成:
#include <atomic>
void barrier_sc(void) {
std::atomic_thread_fence(std::memory_order_seq_cst);
}
Run Code Online (Sandbox Code Playgroud)
86: mfence
。
电源:sync
。
AArch64:(dmb ish
“内部可共享”一致性域的完全障碍)。
ARM 带有gcc -mcpu=cortex-a15
(或-march=armv7
):dmb ish
RISC-V: fence iorw,iorw
void barrier_acq_rel(void) {
std::atomic_thread_fence(std::memory_order_acq_rel);
}
Run Code Online (Sandbox Code Playgroud)
x86:没有
POWER:(lwsync
轻量级同步)。
AArch64:仍然dmb ish
ARM:仍然dmb ish
RISC-V:仍然fence iorw,iorw
void barrier_acq(void) {
std::atomic_thread_fence(std::memory_order_acquire);
}
Run Code Online (Sandbox Code Playgroud)
x86:没有
POWER:(lwsync
轻量级同步)。
AArch64:(dmb ishld
加载屏障,不必排空存储缓冲区)
ARM:仍然dmb ish
,即使使用-mcpu=cortex-a53
(ARMv8):/
RISC-V:仍然fence iorw,iorw
归档时间: |
|
查看次数: |
338 次 |
最近记录: |