据我所知,mfence是一个硬件内存屏障,而asm volatile ("" : : : "memory")是一个编译器屏障。但是,asm volatile ("" : : : "memory")可以用来代替mfence吗?
我感到困惑的原因是this link
发布于 2012-08-31 03:45:16
那么,只有在内存排序较弱的体系结构上才需要内存屏障。x86和x64没有弱内存排序。在x86/x64上,所有存储都有释放围栏,所有加载都有获取围栏。因此,您实际上应该只需要asm volatile ("" : : : "memory")
有关英特尔和AMD的概述以及相关制造商规格的参考资料,请参阅http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
通常,像“易失性”这样的东西是在每个字段的基础上使用的,其中对该字段的加载和存储本身就是原子的。在对字段的加载和存储已经是原子的情况下(即,所讨论的“操作”是对单个字段的加载或存储,因此整个操作是原子的),在x86/x64上不需要volatile字段修饰符或存储器屏障。尽管有可移植的代码。
当涉及到非原子的“操作”时--例如加载或存储到比本机字更大的字段,或者加载或存储到“操作”内的多个字段-这是一种无论CPU体系结构如何都需要将操作视为原子操作的方法。通常,这是通过像互斥锁这样的同步原语来完成的。Mutexes (我用过的那些)包括内存屏障,以避免处理器重新排序等问题,因此您不必添加额外的内存屏障指令。我通常认为不使用同步原语是一种过早的优化;但是,过早优化的本质当然是97%的时间:)
在不使用同步原语并且要处理多字段不变量的情况下,确保处理器不会将存储和加载重新排序到不同的内存位置的内存屏障非常重要。
现在,在asm易失性中不发出"mfence“指令,而是在clobber列表中使用"memory”。从我所能做的read
如果你的汇编指令以不可预知的方式访问内存,请将‘memory’添加到损坏的寄存器列表中。这将导致GCC不将内存值缓存在整个汇编指令的寄存器中,也不会优化对该内存的存储或加载。
当他们说"GCC“而没有提到任何关于CPU的东西时,这意味着它只适用于编译器。缺少"mfence“意味着没有CPU内存屏障。您可以通过反汇编生成的二进制文件来验证这一点。如果没有发出"mfence“指令(取决于目标平台),那么很明显CPU没有被告知发出内存栅栏。
根据你所在的平台和你试图做的事情,可能会有一些“更好的”或更清晰的东西……可移植性不好。
发布于 2015-02-04 03:34:51
asm volatile ("" ::: "memory")只是一个编译器屏障。asm volatile ("mfence" ::: "memory")既是一个编译器屏障,MFENCE__sync_synchronize()也是一个编译器屏障和全内存屏障。因此,asm volatile ("" ::: "memory")本身不会阻止CPU对独立数据指令进行重新排序。正如所指出的,x86-64具有强大的内存模型,但是StoreLoad重新排序仍然是可能的。如果您的算法需要一个完整的内存屏障才能工作,那么您需要__sync_synchronize
发布于 2015-04-10 18:01:05
有两种重新排序,一种是编译器重新排序,另一种是CPU重新排序。
x86/x64具有相对较强的内存模型,但在x86/x64上可能会发生StoreLoad重新排序(较晚的加载通过较早的存储)。请参阅http://en.wikipedia.org/wiki/Memory_ordering
asm volatile ("" ::: "memory")只是一个编译器,barrier.asm volatile ("mfence" ::: "memory")既是编译器的屏障,也是的屏障。
也就是说,只使用编译器屏障,只能防止编译器重新排序,但不能阻止CPU重新排序。这意味着在编译源代码时不会重新排序,但可以在运行时重新排序。
因此,这取决于您的需求,使用哪一个。
https://stackoverflow.com/questions/12183311
复制相似问题