gpt4 book ai didi

c - 为什么我们需要读写屏障?

转载 作者:行者123 更新时间:2023-12-04 11:04:37 25 4
gpt4 key购买 nike

为什么我们需要用相同的实现定义两种类型的障碍?

For example, this code from io_uring in Linux:

#if defined(__x86_64) || defined(__i386__)
#define read_barrier() __asm__ __volatile__("":::"memory")
#define write_barrier() __asm__ __volatile__("":::"memory")
#else

最佳答案

真正的答案是:因为 x86 的内存模型已经足够强大,可以阻塞 compile-time reordering。足以进行加载或存储排序;运行时重新排序已被硬件阻止。

这些只是通过一段内联汇编形成的通用编译时障碍,如果使用的话,可以防止 GCC 重新排序指令。解释的很好in this other post .使用此“技巧”可以实现的目标通常也可以使用 C volatile 限定符实现。

请注意,Linux 内核不会在代码中的任何地方使用这些特定的宏,它们只是为 io_uring 用户空间测试工具定义的两个宏。 It definitely uses asm volatile ("" ::: "memory")在需要的地方,但使用不同的名称(例如 smp_rmb()smp_wmb())。

x86 的内存模型使得 sfencelfence 对于 CPU 之间的通信完全无用;阻止编译时重新排序就足够了:参见 Does the Intel Memory Model make SFENCE and LFENCE redundant?

smp_mb() 是一个完整的屏障,确实需要一个实际的 asm 指令,以及阻止编译时重新排序。


x86 确实有一些内存屏障 asm 指令用于只读和只写“真实”(运行时)内存屏障。它们是 sfence(存储栅栏)、lfence(加载栅栏)和 mfence(内存栅栏 = 全栅栏)。

mfence 序列化读取和写入(完全屏障),而其他只序列化两者之一(读取或写入 a.k.a 加载或存储)。 The wikipedia page关于内存排序在解释这些含义方面做得不错。 lfence 实际上会阻止 LoadStore 重新排序,而不仅仅是 LoadLoad,用于从 WC 内存中弱排序的 movntdqa 加载。已经禁止对来自其他内存类型的其他类型的加载进行重新排序,因此几乎没有任何理由实际使用 lfence 进行内存排序,而不是阻止乱序执行的其他效果。

内核将那些实际的 asm 指令用于 I/O 代码中的内存屏障,例如 mb()rmb()wmb() which expand exactly to mfence, lfence, sfence ,以及其他 ( example )。

sfencelfence 在大多数情况下可能有点矫枉过正,例如围绕 MMIO 到强序 UC 内存。写入 WC 内存实际上可能需要一个 sfence。但与 I/O 相比它们并不太慢,并且在某些情况下可能会出现问题,因此 Linux 采取了安全的方法。

除此之外,x86 有不同类型的读/写屏障,它们也可能更快(例如我上面链接的那个)。有关使用 mfence 或虚拟 locked 指令的完整屏障(C11 称之为顺序一致性)的更多信息,请参阅以下答案:

关于c - 为什么我们需要读写屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61307639/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com