内存屏障

来源:互联网 发布:19岁田径校花网络爆红 编辑:程序博客网 时间:2024/04/27 22:12
set_mb(),mb(),barrier()函数究竟有何作用?
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": ::"memory")
1)set_mb(),mb(),barrier()函数追踪到底,就是 __asm____volatile__("":::"memory"),而这行代码就
是内存屏障。
2)__asm__用于指示编译器在此插入汇编语句
3)__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样

子处理这这里的汇编。
4)memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的
内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,

cache中的数据用于去优化指令,而避免去访问内存。
5)"":::表示这是个空指令。barrier()不用在此插入一条串行化汇编指令。在后文将讨论什么叫串行化指令


6)__asm__,__volatile__,memory在前面已经解释
7)lock前缀表示将后面这句汇编语句:"addl $0,0(%%esp)"作为cpu的一个内存屏障。
8)addl $0,0(%%esp)表示将数值0加到esp寄存器中,而该寄存器指向栈顶的内存单元。加上一个0,esp寄存
器的数值依然不变。即这是一条无用的汇编指令。在此利用这条无价值的汇编指令来配合lock指令,在
__asm__,__volatile__,memory的作用下,用作cpu的内存屏障。


#include <asm/system.h>
"void rmb(void);"
"void wmb(void);"
"void mb(void);"
这些函数在已编译的指令流中插入硬件内存屏障;具体的插入方法是平台相关的。rmb(读内存屏障)保证了屏
障之前的读操作一定会在后来的读操作执行之前完成。wmb 保证写操作不会乱序,mb 指令保证了两者都不会。
这些函数都是 barrier函数的超集。解释一下:编译器或现在的处理器常会自作聪明地对指令序列进行一些处
理,比如数据缓存,读写指令乱序执行等等。如果优化对象是普通内存,那么一般会提升性能而且不会产生逻
辑错误。但如果对 I/O操作进行类似优化很可能造成致命错误。所以要使用内存屏障,以强制该语句前后的指
令以正确的次序完成。其实在指令序列中放一个wmb的效果是使得指令执行到该处时,把所有缓存的数据写到该
写的地方,同时使得wmb前面的写指令一定会在wmb的写指令之前执行。
 

cpu上有一根pin #HLOCK连到北桥,lock前缀会在执行这条指令前先去拉这根 pin,持续到这个指令结束时放开
#HLOCK pin,在这期间,北桥会屏蔽掉一切外设以及AGP的内存操作。也就保证了这条指令的atomic。

sfence:在sfence指令前的写操作,必须在 sfence指令后的写操作前完成。
lfence:在lfence指令前的读操作,必须在lfence指令后的读操作前完成。
mfence:在mfence指令前的读写操作,必须在mfence指令后的读写操作前完成。

在内核中,内存屏障多用在各种锁(如spin_lock)的实现上,其他的需要保证执行顺序,或需要强制使缓存数据失效的地方也有使用。
0 0