如果是这样,那么内存屏障(例如C++11中的std::atomic_thread_fence)是否也不会涉及内核呢?
在几乎所有正常的CPU上(我们在现实生活中编写程序的那种),内存屏障指令是非特权的,直接由编译器使用。编译器知道如何生成像x86 lock add [rdi], eax
这样的指令来执行fetch_add
(或者如果您使用返回值,则使用lock xadd
)。或者在其他ISA上,它们使用相同的屏障指令在加载、存储和RMWs之前/之后进行排序。https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/
在任意假设的硬件和/或编译器上,当然可以发生任何事情,即使对性能造成灾难性影响。
在汇编语言中,屏障只是使此核心等待,直到一些先前的(程序顺序)操作对其他核心可见为止。这是一个纯本地操作。(至少,这是实际CPU的设计方式,以便通过控制本地加载和/或存储操作的本地排序来恢复顺序一致性。所有核心共享一个一致的缓存视图,通过类似MESI的协议维护。非一致的共享内存系统存在,但实现不会在它们之间运行C++ std::thread,并且通常不会运行单一系统映像内核。)
注1:(即使是非无锁原子操作通常也使用轻量级锁定)。
此外,ARMv7之前的ARM显然没有适当的内存屏障指令。 在ARMv6上,GCC使用mcr p15,0,r0,c7,c10,5
作为屏障。
在此之前(g++ -march=armv5
及更早版本),GCC不知道该怎么做,并调用__sync_synchronize
(一个libatomic GCC辅助函数),希望它在代码实际运行的任何机器上都能够实现。这可能涉及到一个假设的ARMv5多核系统上的系统调用,但更有可能的是二进制文件将在ARMv7或v8系统上运行,其中库函数可以运行dmb ish
。或者如果它是单核系统,则可能是无操作,我想。(C++内存排序关心其他C++线程,而不关心可能的硬件设备/ DMA所看到的内存顺序。通常实现假定是多核系统,但这个库函数可能是一个单核系统的情况下可以使用的例子。)
std::atomic_thread_fence(std::memory_order_seq_cst)
编译成了mfence
。较弱的屏障例如std::atomic_thread_fence(std::memory_order_release)
只需要阻止编译时的重新排序;x86的运行时硬件内存模型已经是acq/rel (seq-cst + 存储缓冲器),所以没有与屏障相对应的汇编指令。(C++库的一种可能实现是GNU C asm("" ::: "memory");
,但GCC / clang确实有内置的屏障。)
std::atomic_signal_fence
只需阻止编译时的重新排序,即使在弱序的ISA上也是如此,因为所有真实的ISA都保证单个线程内的执行都按照程序顺序进行。(硬件通过在当前核心的存储缓冲区中监视加载操作来实现此操作)。具有延迟可见性加载的VLIW和IA-64 EPIC或其他显式并行ISM机制(例如Mill)仍然使得编译器可以生成遵守任何涉及屏障的C ++排序保证的代码,如果异步信号(或内核代码的中断)在任何指令之后到达。#include <atomic>
void barrier_sc(void) {
std::atomic_thread_fence(std::memory_order_seq_cst);
}
x86: mfence
(内存屏障)
POWER:sync
(同步指令)
AArch64:dmb ish
(在“内部可共享”一致性域上进行完整的屏障操作)
使用gcc -mcpu=cortex-a15
或者-march=armv7
编译的ARM:dmb ish
RISC-V: fence iorw,iorw
(内存栅栏指令)
void barrier_acq_rel(void) {
std::atomic_thread_fence(std::memory_order_acq_rel);
}
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);
}
x86:无需操作
POWER:lwsync
(轻量级同步)
AArch64:dmb ishld
(加载屏障,不必清空存储缓冲区)
ARM:即使使用-mcpu=cortex-a53
(一个ARMv8),仍然是dmb ish
:/
RISC-V:仍然是fence iorw,iorw
mutex
和atomic
之间的区别,特别是它们的性能。如果atomic
和内存屏障不涉及内核,至少我可以确保atomic
+内存屏障会产生更少的上下文切换。 - Yvesstd::atomic_thread_fence
,它通常不会在X86上调用任何操作系统函数。但是,您可以简单地查看编译器生成的代码。如果编译器发出了一些OS调用,您将看到所有OS调用。 - Klaus