英特尔SFENCE是否具有发布语义?

rya*_*ner 15 concurrency multithreading memory-barriers

似乎接受和释放语义的公认定义是这样的:(引自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的定义,它似乎没有提供发布语义,因为它根本不与负载同步?而我所理解的释放语义定义了关于所有内存操作(加载和存储)的排序.

Arc*_*son 20

LFENCE没有获得语义; SFENCE没有发布语义.这有一个很好的理由:拥有一个带有获取语义或释放语义的独立fence指令,结果几乎完全没用.为了获得/释放任何好处,它必须与内存操作联系起来.

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

  1. 处理器A写入缓冲区.
  2. 处理器A将"true"写入标志.
  3. 处理器B等待,直到标志为真.
  4. 处理器B读取缓冲区.

请注意,处理器A必须确保写入缓冲区才能看到对该标志的写入.现在假设我们有一个"RFENCE"指令,它是一个释放围栏.如果我们在步骤(1)之后立即执行该指令,则没有任何好处,因为允许步骤2中的写入在RFENCE上向上迁移并在步骤1中向上迁移.

类似的论点表明,执行获取的"AFENCE"指令同样无用于确保步骤3中的标志读取似乎不会在步骤4中向下迁移.

Itanium通过提供write-with-release和load-with-acquire指令将范围与内存操作联系起来,从而优雅地解决了这个问题.

回到IA-32和Intel64:如果程序不使用"非时间"指令,则其余指令的行为就好像每个负载都执行"获取"并且每个存储都执行"释放".请参阅英特尔®64和IA-32架构开发人员手册:Vol.第8.2.3节(和小节).3A.如果涉及"非临时"商店,您可以通过多种方式强制执行范围:

  • 使用SFENCE
  • 使用MFENCE - 有点矫枉过正
  • 使用LOCK前缀指令(例如"LOCK INC")写入标志.LOCK前缀指令隐式具有MFENCE.
  • 使用XCHG(就像它具有隐式LOCK前缀一样)来写入标志.

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

以上所有评论均适用于硬件.使用高级语言时,请确保编译器不会损坏事件的关键顺序.存在C++ 11原子操作库,以便您可以告诉编译器硬件您想要什么.

  • 您是正确的,SFENCE没有发布语义;但是,事实证明,根据定义,LFENCE确实至少根据您引用的手册的第8.2.2节提供了获取(LoadLoad + LoadStore)语义。在具有比x86独立屏障弱的一致性模型的体系结构上,*用于*确保一致性,例如SPARC-V9的`membar #LoadLoad |。#LoadStore`(用于获取)和`member #LoadStore | #StoreStore`(用于发布)。尽管获取和释放语义应该与任何内存操作相关才能有用,但这并不意味着此类障碍没有任何用处。 (2认同)