C++ 内存围栏是否涉及内核

C++ 内存围栏是否涉及内核,c++,performance,atomic,memory-barriers,stdatomic,C++,Performance,Atomic,Memory Barriers,Stdatomic,问过之后,我明白了原子指令,比如测试和设置,不会涉及内核。只有当一个进程需要进入睡眠(等待获取锁)或唤醒(因为它无法获取锁,但现在可以),内核才能参与执行调度操作 如果是这样,这是否意味着内存围栏,例如c++11中的std::atomic_thread_fence,将不会涉及内核?在这个问题和您正在混合的引用问题中: 在汇编程序范围内的同步原语,如和fences 进程/线程同步,如 “它涉及内核”是什么意思?我猜您的意思是“(p)线程同步”:线程处于睡眠状态,并且在另一个进程/线程满足给定条

问过之后,我明白了原子指令,比如
测试和设置
,不会涉及内核。只有当一个进程需要进入睡眠(等待获取锁)或唤醒(因为它无法获取锁,但现在可以),内核才能参与执行调度操作


如果是这样,这是否意味着内存围栏,例如c++11中的
std::atomic_thread_fence
,将不会涉及内核?

在这个问题和您正在混合的引用问题中:

  • 在汇编程序范围内的同步原语,如和fences
  • 进程/线程同步,如
“它涉及内核”是什么意思?我猜您的意思是“(p)线程同步”:线程处于睡眠状态,并且在另一个进程/线程满足给定条件时将立即唤醒

但是,测试和设置原语(如和内存围栏)是由微处理器汇编程序提供的功能。内核同步原语最终基于它们来提供系统和进程同步,使用隐藏在内核调用后面的内核空间中的共享状态

你可以看看这些证据

但是不,内存围栏不涉及内核:它们被转换为。与cmpxchg相同。

std::atomic不涉及内核1 在几乎所有的普通CPU(我们在现实生活中为之编程的类型)上,内存屏障指令都是非特权指令,编译器可以直接使用。同样的方式,编译器知道如何发出x86
lock add[rdi]、eax
for
fetch\u add
(或者
lock xadd
,如果使用返回值). 或在其他ISA上,与加载、存储和RMW之前/之后用于提供所需顺序的屏障指令完全相同。

在一些任意假设的硬件和/或编译器上,任何事情当然都是可能的,即使这会对性能造成灾难性的影响

在asm中,屏障只会使该内核等待,直到其他内核可以看到以前的一些(程序顺序)操作。这是一个纯本地操作。(至少,这是真实的字CPU如何被设计,使得顺序一致性仅通过本地的障碍来恢复,以控制负载和/或存储操作的本地排序。所有的核共享高速缓存的一致视图,通过像MESI这样的协议来维护。非相干共享内存系统存在,但是实现不运行C++ STD::它们通常不运行单个系统映像内核。)

脚注1:(即使是非无锁原子也通常使用轻质锁)

而且,ARMv7之前的ARM显然没有正确的内存屏障指令。在ARMv6上,GCC使用mcr p15、0、r0、c7、c10、5作为屏障。
在此之前(
g++-march=armv5
及更早版本),GCC不知道该做什么,并调用
\uuu sync\u synchronize
(libatomic GCC助手函数),希望无论代码实际运行在什么机器上,它都能以某种方式实现。这可能涉及对假设的ARMv5多核系统的系统调用,但更有可能的是,二进制文件将在ARMv7或v8系统上运行,其中库函数可以运行
dmb ish
。或者,如果它是一个单核心系统,那么它可能是一个不可操作的,我认为。(C++内存排序关心其他C++线程,而不是关于可能的硬件设备/ DMA所看到的内存顺序。通常实现假定为多核系统,但该库函数可能是只使用单核实现的情况。)
例如,在x86上,
std::atomic\u thread\u fence(std::memory\u order\u seq\u cst)
编译为
mfence
。较弱的障碍,如std::atomic\u thread\u fence(std::memory\u order\u release)
只需要阻止编译时重新排序;x86的运行时硬件内存模型已经是acq/rel(seq cst+a存储缓冲区)。因此,没有任何asm指令与屏障相对应。(C++库的一种可能实现方式是GNU C代码> ASM(“:”::“内存”);< /C> >,但GCC/CLAN确实有障碍物构建。
std::atomic\u signal\u fence
只需阻止编译时重新排序
,即使在弱顺序的ISA上也是如此,因为所有真实世界的ISA都保证在单个线程内执行时会看到自己的操作按程序顺序发生。(硬件通过让负载嗅探当前内核的存储缓冲区来实现这一点)。VLIW和IA64 64 EPIC或其他显式并行性是一种机制(如MLL的延迟可见性负载),编译器仍然可以生成代码,该代码遵守任何C++命令保证,如果异步指令(或内核代码中断)在任何指令之后到达,则涉及到障碍。
您可以自己查看代码gen:

x86:无
电源:
lwsync
(轻型同步)。
AArch64:仍然
dmb ish

ARM:仍然
dmb ish

RISC-V:仍然
围栏iorw,iorw

void barrier_acq_rel(void) {
    std::atomic_thread_fence(std::memory_order_acq_rel);
}
void barrier_acq(void) {
    std::atomic_thread_fence(std::memory_order_acquire);
}
x86:无
电源:
lwsync
(轻型同步)。
AArch64:
dmb ishld
(加载屏障,不必排空存储缓冲区)
ARM:仍然
dmb ish
,即使使用
-mcpu=cortex-a53
(ARMv8):/

RISC-V:仍然
围栏iorw,iorw

你能解释一下为什么你想知道实现细节吗?作为给定系统(OS/编译器/库)的用户,您不能更改行为。如果你需要同步内存访问,你必须使用它。我只是想知道任何类型的答案都会如何改变你的代码或其他什么。。。Thanks@Klaus因为优化。基于汇编程序的同步原语的延迟约为100个周期(数量级)
void barrier_acq_rel(void) {
    std::atomic_thread_fence(std::memory_order_acq_rel);
}
void barrier_acq(void) {
    std::atomic_thread_fence(std::memory_order_acquire);
}