内存防护是否会阻塞多核CPU中的线程?

时间:2018-08-12 13:05:18

标签: multithreading x86 multicore memory-barriers

我正在阅读Intel指令集指南64-ia-32 guide 在记忆栅栏上有个主意。我的问题是,对于带有SFENCE的示例,为了确保所有存储操作都是全局可见的,多核CPU是否将所有线程甚至在其他内核上运行都停泊了,直到实现缓存一致性为止?

1 个答案:

答案 0 :(得分:1)

障碍不会使其他线程/内核等待。它们使当前线程中的某些操作处于等待状态,具体取决于它的屏障类型。非内存指令的乱序执行不一定会被阻止。

障碍甚至无法使您的加载/存储对其他线程更快地可见; CPU内核已经尽快将存储缓冲区中的存储提交(退出)到L1d高速缓存中。 (在遵循了所有必要的MESI一致性规则之后,x86的强大内存模型仅允许存储以程序顺序提交,即使没有障碍也是如此。)

障碍不一定命令指令执行,而是命令全局可见性,即存储缓冲区的末端。


mfence(或类似lock addxchg [mem], reg的{​​{3}})使所有以后在 current 线程中的加载/存储都等到之前的所有加载和存储已完成并且在全局可见(即存储缓冲区已刷新)。

Skylake上的

mfence的实现方式是使整个内核停止运行,直到存储缓冲区耗尽(但 not lock ed操作)。看到我的答案 locked operation了解详情。但是lock版的操作和xchg并非如此;它们是完整的内存屏障,但是它们仍然允许imul eax, edx的无序执行,因此我们有证据表明它们不会使整个内核停滞不前。

使用超线程,我认为这种停滞发生在每个逻辑线程上,而不是整个核心上。

但是请注意,mfence手动输入并没有说明停止内核,因此将来的x86实现可以自由地使其效率更高(例如lock or dword [rsp], 0),并且只能防止以后的加载读取L1d缓存而不会阻止以后的非加载指令。


Are loads and stores the only instructions that gets reordered?仅在有任何NT商店正在运行时才执行任何操作。它根本不排序加载,因此不必停止后续指令的执行。参见sfence

它只是在存储缓冲区中放置一个屏障,以阻止NT存储区对其重新排序,并迫使更早的NT存储区在sfence屏障可以离开存储缓冲区之前是全局可见的。 (即写合并缓冲区必须刷新)。但是它可以在到达存储缓冲区的末尾之前从内核的无序执行部分(ROB或ReOrder Buffer)中退出。)

另请参阅Why is (or isn't?) SFENCE + LFENCE equivalent to MFENCE?


Does a memory barrier ensure that the cache coherence has been completed?作为内存屏障几乎是无用的:它只能防止WC内存中的movntdqa加载随以后的加载/存储而重新排序。您几乎永远不需要它。

lfence的实际用例主要涉及其Intel(但不是AMD)行为,该行为直到其本身退出使用才允许以后的指令执行。 (因此,在Intel CPU上使用lfence; rdtsc可以避免rdtsc读取时钟太早,这是cpuid; rdtsc的更便宜的选择)

lfence最近的另一个重要用例是阻止推测执行(例如在条件分支或间接分支之前),以减少Spectre。这完全基于Intel保证的部分序列化的副作用,与它的LoadLoad + LoadStore屏障效果无关。

lfence不必 等待存储缓冲区耗尽才可以从ROB退出,因此LFENCE + SFENCE的组合没有像MFENCE那样强大。 lfence


相关内容:Why is (or isn't?) SFENCE + LFENCE equivalent to MFENCE? (使用C ++而不是asm编写时)。

请注意,像_mm_sfence这样的C ++内在函数也会阻塞编译时内存的排序。即使没有asm指令本身,这通常也是必要的,因为C ++的编译时重排序是基于C ++的非常弱的内存模型而不是强大的x86内存模型(适用于编译器生成的asm)进行的。

因此_mm_sfence可以使您的代码正常工作,但是除非您使用NT存储,否则它会显得过大。更有效率的选择是std::atomic_thread_fence(std::memory_order_release)(变成零指令,只是编译器障碍。)请参见When should I use _mm_sfence _mm_lfence and _mm_mfence