我的代码如下所示。我发现了读和写的rmb和wmb,但没有找到通用的方法。lwsync在PowerPC上可用,但在x86上有什么替代品呢?提前感谢。
#define barrier() __asm__ volatile ("lwsync")
...
lock()
if(!pInst);
{
T* temp=new T;
barrier();
pInst=temp;
}
unlock();
我的代码如下所示。我发现了读和写的rmb和wmb,但没有找到通用的方法。lwsync在PowerPC上可用,但在x86上有什么替代品呢?提前感谢。
#define barrier() __asm__ volatile ("lwsync")
...
lock()
if(!pInst);
{
T* temp=new T;
barrier();
pInst=temp;
}
unlock();
rmb()
和wmb()
是Linux内核函数。还有mb()
。
我记得x86指令是lfence
、sfence
和mfence
。
在 Cilk 运行时中,有一个特定的文件可能会引起您的兴趣,即 cilk-sysdep.h,其中包含与内存屏障相关的系统特定映射。我提取了一个关于 x86 的小节,与您的问题相关,即 i386。
文件:-- cilk-sysdep.h(左侧的数字实际上是行号)
*我们使用xchg指令序列化内存访问,可以根据英特尔架构软件开发人员手册第3卷:系统编程指南进行操作 *(http://www.intel.com/design/pro/manuals/243192.htm),第7-6页, *“对于P6系列处理器,锁定操作会序列化所有未完成的加载和存储操作(即等待它们完成)。” *xchg指令默认是一个锁定操作。 *请注意,推荐的内存屏障是cpuid指令,这个指令非常慢(~70个周期)。相比之下, *xchg只需要大约23个周期(加上每个写缓冲区的几个?)仍然很慢,但这是我能找到的最好的方法。 -KHR * *Bradley还计时了“mfence”,在Pentium IV xchgl上速度要快得多 *mfence似乎需要在2.5GHZ P4上花费约125纳秒 *xchgl 似乎需要在2.5GHZ P4上花费约90纳秒 *但是在opteron上,mfence和xchgl的性能都很好。 *mfence在1.5GHZ AMD64上只需要8ns(也许这是801) *sfence需要5ns *lfence需要3ns *xchgl需要14ns *查看mfence-benchmark.c */ int x = 0,y; __asm__ volatile ("xchgl %0,%1" :"=r"(x) :"m"(y),"0"(x) :"memory"); }
我喜欢的是xchgl似乎更快 :) 不过你应该真正实现它们并检查一下。
在这段代码中,您没有明确说明锁定和解锁是什么。我假设它们是互斥操作。在PowerPC上,互斥获取函数将使用isync(如果没有该硬件,则可能在lock()之前评估if(!pInst)),并且在unlock()中将具有lwsync(或sync,如果您的互斥实现过时)。
因此,假设您对pInst的所有访问(读取和写入)都受到锁定和解锁方法的保护,则您的屏障使用是多余的。解锁将具有足够的屏障,以确保在解锁操作完成之前pInst存储可见(因此,在使用相同的锁定的情况下,它将在任何后续锁定获取之后可见)。
在x86和x64上,您的lock()将使用某种形式的LOCK前缀指令,该指令自动具有双向栅栏行为。
在x86和x64上,您的解锁只需要是一个存储指令(除非您在CS中使用一些特殊的字符串指令,在这种情况下,您将需要一个SFENCE)。
手册:
这个内容包含有关所有障碍以及LOCK前缀的影响的良好信息(以及何时暗示使用该前缀)。
附注:在解锁代码中,您还必须有一些强制编译器排序的东西(因此,如果只是存储零,则还需要类似于GCC样式的asm _volatile_("" ::: "memory"))。
asm volatile ("whatever":::memory);
告诉 GCC 任意内存地址可能已被破坏。我认为仅仅发出指令并不足够,如果 GCC 将加载缓存在寄存器中。 - tc.lwsync
是一个无操作指令,因为它没有像ARM、PPC和Alpha那样弱的内存模型。请参见Herding cats..第4.6节。对于IBM文档中的lwsync
,确保在执行函数的处理器上执行任何后续存储指令之前,调用__lwsync之前的所有指令都已经完成。 它只针对单个核心,而不是整个SMP系统。所以,它实际上是为了使流水线与O-O执行同步。 - artless noise