zoukankan      html  css  js  c++  java
  • 关于MemoryBarrier

    备注:OSG  OpenThread::Atomic.cpp中MemoryBarrier();

    Atomic::operator unsigned() const
    {
    #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
        __sync_synchronize();
        return _value;
    #elif defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED)
        MemoryBarrier();
        return _value;
    #elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC)
        OSMemoryBarrier();
        return static_cast<unsigned const volatile>(_value);
    #else
    # error This implementation should happen inline in the include file
    #endif
    }

    MemoryBarrier();保证函数返回的值,直接从内存中读取,而不是从寄存器中读取;

    
    

    内核中定义的内存屏障原语有: 

    #define barrier() __asm__ __volatile__("": : :"memory") #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() #define smp_read_barrier_depends() read_barrier_depends() #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) #else #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() #define smp_read_barrier_depends() do { } while(0) #define set_mb(var, value) do { var = value; barrier(); } while (0) #endif 1). smp_xxx()和xxx()的差别 为了给其他CPU也提供相关的barrier宏。 比如x86的rmb()是用了lfence指令,但其他CPU不能用这个指令。 2). 关于barrier()宏,jkl大师是这么说的: CPU越过内存屏障后,将刷新自己对存储器的缓冲状态。这条语句实际上不生成不论什么代码,但可使gcc在 barrier()之后刷新寄存器对变量的分配。 也就是说,barrier()宏仅仅约束gcc编译器,不约束执行时的CPU行为。 举例: 1 int a = 5, b = 6; 2 barrier(); 3 a = b; 在line 3,GCC不会用存放b的寄存器给a赋值,而是invalidate b的Cache line,又一次读内存中的b值,赋值给a。 3). mb() vs. rmb() vs. wmb() rmb()不同意读操作穿过内存屏障;wmb()不同意写操作穿过屏障;而mb()二者都不同意。 看IA32上wmb()的定义: #ifdef CONFIG_X86_OOSTORE #define wmb() alternative("lock;addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM); #else #define wmb() __asm__ __volatile__ ("": : :"memory"); #endif Intel和AMD都没有在IA32 CPU中实现乱序写(Out-Of-Order Store),所以wmb()定义为空操作,不约束CPU行为;但 有些IA32 CPU厂商实现了OOO Store,所以就有了使用sfence的那个wmb()实现。 
    总线加锁的功能是保证程序运行的顺序不乱掉, 
    
    
    一旦加LOCK指令了,CPU会将此指令前的读写操作都串行完毕,这最基本的作用是使CPU的预取等无效了。 
    
    
    在这个串行操作中,MESI协议会起作用。 
    
    
    但保证全部CPU的Cache一致性的是MESI协议,这是硬件上保证的。 
    
    
    barrier是对GCC编译器做约束,是软件层次上的。 
    
    
    “因此barrier就能保证全部CPU的Cache一致性”这样的说法是不正确的。 
    
    
    
    
    lock指令保证程序运行的顺序不乱掉,没有将“本CPU的Cache写入了内存”的功能。 
    
    
    总线监视功能是由各个CPU的CACHE完毕的, 
    
    
    这个功能能够算是MESI协议的实现。MESI保证了SMP下的CACHE一致性。 
    
    
    
    MESI协议 

    包含IA32的很多体系结构的CPU,为了保证缓存一致性,实现了MESI协议。 

    M: Modified,已改动 
    E: Exclusive,排他 
    S: Shared,共享 
    I: Invalid,无效 

    IA32 的CPU实现了MESI协议来保证Cache coherence。 CPU的总线监測单元,始终监视着总线上全部的内存写操作, 
    以便随时调整自己的Cache状态。 

    -> Modified。 本CPU写,则直接写到Cache,不产生总线事物;其他CPU写,则不涉及本CPU的Cache,其他CPU 
    读,则本CPU须要把Cache line中的数据提供给它,而不是让它去读内存。 

    -> Exclusive。仅仅有本CPU有该内存的Cache,并且和内存一致。 本CPU的写操作会导致转到Modified状态。 

    -> Shared。 多个CPU都对该内存有Cache,并且内容一致。不论什么一个CPU写自己的这个Cache都必须通知其他 
    的CPU。 

    -> Invalid。 一旦Cache line进入这个状态,CPU读数据就必须发出总线事物,从内存读。 


    5) 考虑到DMA 

    5.1). Wirte through策略。 这样的情形比較简单。 

    -> 本CPU写内存,是write through的,因此不管什么时候DMA读内存,读到的都是正确数据。 
    -> DMA写内存,假设DMA要写的内存被本CPU缓存了,那么必须Invalidate这个Cache line。下次CPU读它,就 
    直接从内存读。 

    5.2). Write back策略。 这样的情形相当复杂。 

    -> DMA读内存。被本CPU总线监视单元发现,并且本地Cache中有Modified数据,本CPU就截获DMA的内存读操作, 
    把自己Cache Line中的数据返回给它。 

    -> DMA写内存。并且所写的位置在本CPU的Cache中,这又分两种情况: 
    a@ Cache Line状态未被CPU改动过(即cache和内存一致),那么invalidate该cache line。 
    b@ Cache Line状态已经被改动过,又分2种情况: 

    <1> DMA写操作会替换CPU Cache line所相应的整行内存数据,那么DMA写,CPU则invalidate 
    自己的Cache Line。 
    <2> DMA写操作仅仅替换Cache Line相应的内存数据的一部分,那么CPU必须捕获DMA写操作的新 
    数据(即DMA想把它写入内存的),用来更新Cache Line的相关部分。
    
    
    
  • 相关阅读:
    神经网络 初步
    SVM整理
    碎碎念
    random note
    2015阿里实习内推一轮被拒
    django开发框架-view & template
    一点思考
    dive into python 读笔(3)
    dive into python 读笔(2)
    dive into python 读笔(1)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4022822.html
Copyright © 2011-2022 走看看