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指令,结果几乎完全没用.为了获得/释放任何好处,它必须与内存操作联系起来.
例如,考虑在两个线程之间发送数据的常用习惯用法:
请注意,处理器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.如果涉及"非临时"商店,您可以通过多种方式强制执行范围:
例如,如果在较早的习语中,缓冲区是使用非临时存储编写的,则处理器A在步骤1和2之间发出SFENCE或MFENCE.或者使用XCHG写入标志.
以上所有评论均适用于硬件.使用高级语言时,请确保编译器不会损坏事件的关键顺序.存在C++ 11原子操作库,以便您可以告诉编译器和硬件您想要什么.