【问题标题】:Does Intel SFENCE have release semantics?英特尔 SFENCE 是否具有发布语义?
【发布时间】:2013-04-10 21:39:46
【问题描述】:

似乎公认的获取和释放语义定义是这样的: (引自http://msdn.microsoft.com/en-us/library/windows/hardware/ff540496(v=vs.85).aspx

如果其他处理器总是会看到,则操作具有获取语义 其在任何后续操作的效果之前的效果。一个操作有 如果其他处理器将看到前面的每一个,则释放语义 操作的效果先于操作本身的效果。

我已经简要了解了半内存屏障的存在,据推测它们具有遵循上述相同语义的获取屏障和释放屏障的味道。

查找我遇到 SFENCE 的硬件指令的真实示例。而这个博客(http://peeterjoot.wordpress.com/2009/12/04/intel-memory-ordering-fence-instructions-and-atomic-operations/)说这是一种释放栅栏/屏障:

英特尔提供了一个双向栅栏指令 MFENCE,一个获取 围栏 LFENCE 和释放围栏 SFENCE。

但是阅读 SFENCE 的定义,它似乎没有提供释放语义,因为它根本不与加载同步?而据我所知,发布语义定义了所有内存操作(加载和存储)的顺序。

【问题讨论】:

    标签: multithreading concurrency memory-barriers


    【解决方案1】:

    LFENCE 没有获取语义; SFENCE 没有发布语义。有一个很好的理由:拥有一个具有获取语义或释放语义的独立栅栏指令几乎完全没有用。为了使获取/释放有任何好处,它必须与内存操作相关联。

    例如,考虑在两个线程之间发送数据的常用习语:

    1. 处理器 A 写入缓冲区。
    2. 处理器 A 将“真”写入标志。
    3. 处理器 B 一直等到标志为真。
    4. 处理器 B 读取缓冲区。

    请注意,处理器 A 必须确保在它写入缓冲区之后看到它对标志的写入。现在假设我们有一个“RFENCE”指令,它是一个释放栅栏。如果我们将指令紧跟在第 (1) 步之后,那就没有用了,因为第 2 步中的写入被允许出现在 RFENCE 上方和第 1 步上方的迁移。

    类似的论点表明,执行获取的“AFENCE”指令对于确保在步骤 3 中读取的标志看起来不会向下迁移到步骤 4,同样无用。

    Itanium 通过提供 write-with-release 和 load-with-acquire 指令优雅地解决了这个问题,这些指令将栅栏与内存操作联系起来。

    回到 IA-32 和 Intel64:如果一个程序不使用“非临时”指令,那么其余指令的行为就像每次加载都执行“获取”并且每个存储执行“发布”。请参阅Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3A 的第 8.2.3 节(和小节)。如果涉及“非临时”存储,您有几种方法可以强制执行围栏:

    • 使用 SFENCE
    • 使用 MFENCE - 有点矫枉过正
    • 使用以 LOCK 为前缀的指令(例如“LOCK INC”)写入标志。带有 LOCK 前缀的指令隐含地具有 MFENCE。
    • 使用 XCHG 来写入标志,就像它具有隐式 LOCK 前缀一样。

    例如,如果在前面的习语中,缓冲区是使用非临时存储写入的,则让处理器 A 在步骤 1 和 2 之间发出 SFENCE 或 MFENCE。或者使用 XCHG 来写入标志。

    以上所有说明均适用于硬件。使用高级语言时,请确保编译器不会破坏事件的关键顺序。存在 C++11 原子操作库,以便您可以告诉编译器硬件您的意图。

    【讨论】:

    • "例如,如果在前面的习语中,缓冲区是使用非临时存储写入的,则让处理器 B 在步骤 1 和 2 之间发出 SFENCE 或 MFENCE。或者使用 XCHG 写入标志。 " - 我认为您的意思是处理器 A 而不是 B
    • @StuartGillibrand:感谢您发现错误。我已更正它并更正了错误的“它是”->“它”。
    • 你说得对,SFENCE 没有发布语义;但是,事实证明,根据定义,LFENCE 至少根据您引用的手册的第 8.2.2 节提供了获取(LoadLoad + LoadStore)语义。在一致性模型弱于 x86 独立障碍的架构上用于确保一致性,例如 SPARC-V9 的membar #LoadLoad | #LoadStore(用于获取)和membar #LoadStore | #StoreStore(用于发布)。尽管获取和释放语义应该与任何有用的内存操作相关,但这并不意味着这些障碍没有任何用处。
    • 澄清一下,这样的障碍——用你的话来说——应该被认为是“绑定”到执行顺序之前或成功的相关指令。加载-获取操作等效于加载后跟获取屏障(完全按照该顺序),而存储-释放操作可以替换为释放屏障后跟存储。任何对此主题感兴趣的人也可能会发现this answer 很有帮助。
    猜你喜欢
    • 2015-12-18
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    相关资源
    最近更新 更多