优化屏障

编译器编译源代码时,会将源代码进行优化,将源代码的指令进行重排序,以适合于CPU的并行执行。然而,内核同步必须避免指令重新排序,优化屏障(Optimization barrier)避免编译器的重排序优化操作,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。
Linux用宏barrier实现优化屏障,gcc编译器的优化屏障宏定义列出如下(在include/linux/compiler-gcc.h中):

#define barrier() __asm__ __volatile__("": : :"memory")

上述定义中,“__asm__”表示插入了汇编语言程序,“__volatile__”表示阻止编译器对该值进行优化,确保变量使用了用户定义的精确地址,而不是装有同一信息的一些别名。“memory”表示指令修改了内存单元。

内存屏障

软件可通过读写屏障强制内存访问次序。读写屏障像一堵墙,所有在设置读写屏障之前发起的内存访问,必须先于在设置屏障之后发起的内存访问之前完成,确保内存访问按程序的顺序完成。
读写屏障通过处理器构架的特殊指令mfence(内存屏障)、lfence(读屏障)和sfence(写屏障)完成,见《x86-64构架规范》一章。另外,在x86-64处理器中,对硬件进行操作的汇编语言指令是“串行的”,也具有内存屏障的作用,如:对I/O端口进行操作的所有指令、带lock前缀的指令以及写控制寄存器、系统寄存器或调试寄存器的所有指令(如:cli和sti)。
Linux内核提供的内存屏障API函数说明如表2。内存屏障可用于多处理器和单处理器系统,如果仅用于多处理器系统,就使用smp_xxx函数,在单处理器系统上,它们什么都不要。
表2 内存屏障API函数说明

内存屏障的宏定义 功能说明
mb() 适用于多处理器和单处理器的内存屏障。
rmb() 适用于多处理器和单处理器的读内存屏障。
wmb() 适用于多处理器和单处理器的写内存屏障。
smp_mb() 适用于多处理器的内存屏障。
smp_rmb() 适用于多处理器的读内存屏障。
smp_wmb() 适用于多处理器的写内存屏障。

适合于多处理器和单处理器的内存屏障宏定义列出如下(在include/asm-x86/system.h中):

#ifdef CONFIG_X86_32
/*指令“lock; addl $0,0(%%esp)”表示加锁,把0加到栈顶的内存单元,该指令操作本身无意义,但这些指令起到内存屏障的作用,让前面的指令执行完成。具有XMM2特征的CPU已有内存屏障指令,就直接使用该指令*/
    #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
    #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
    #define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
#else
    #define mb() asm volatile("mfence":::"memory")
    #define rmb() asm volatile("lfence":::"memory")
    #define wmb() asm volatile("sfence" ::: "memory")
#endif

/*刷新后面的读所依赖的所有挂起读操作,在x86-64构架上不需要*/
#define read_barrier_depends() do { } while (0)

宏定义ead_barrier_depends()刷新后面的读所依赖的所有挂起读操作,后面的读操作依赖于正处理的读操作返回的数据。在x86-64构架上不需要此宏。它表明:在此屏障之前,没有来自内存区域数据所依赖的读曾经重排序。所有的读操作处理此原语,保证在跟随此原语的任何读操作此原语之前访问内存(但不需要其他CPU的cache)。此原语在大多数CPU上有比rmb()更轻的份量。
本地CPU和编译器遵循内存屏障的排序限制,仅内存屏障原语保证排序,即使数据有依赖关系,也不能保证排序。例如:下面代码将强迫排序,因为*q的读操作依赖于p的读操作,并且这两个读操作被read_barrier_depends()分开。在CPU 0和CPU 1上执行的程序语句分别列出如下:

CPU 0                                      CPU 1 
b = 2;
memory_barrier();
p = &b;                                      q = p;
                                                read_barrier_depends();
                                                d = *q;

下面的代码没有强制排序,因为在a和b的读操作之间没有依赖关系,因此,在一些CPU上,如:Alpha,y将设置为3,x设置为0。类似这种没有数据依赖关系的读操作,需要排序应使用rmb()。

CPU 0                                        CPU 1

a = 2;
memory_barrier();
b = 3;                                         y = b;
                                                 read_barrier_depends();
                                                 x = a;

适合于多处理器的内存屏障宏定义列出如下(在include/asm-x86/system.h中):

#ifdef CONFIG_SMP
    #define smp_mb() mb()


    #ifdef CONFIG_X86_PPRO_FENCE
        # define smp_rmb() rmb()
    #else
        # define smp_rmb() barrier()
    #endif


    #ifdef CONFIG_X86_OOSTORE
        # define smp_wmb() wmb()
    #else
        # define smp_wmb() barrier()
    #endif


    #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

函数rdtsc_barrier用于加内存屏障阻止RDTSC猜测,当在一个定义的代码区域使用读取时间戳计数器(Read Time-Stamp Counter,RDTSC)函数(或者函数get_cycles或vread)时,必须加内存屏障阻止RDTSC猜测。其列出如下:

static inline void rdtsc_barrier(void)
{
    alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC);
    alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
}

内核同步机制-优化屏障和内存屏障相关推荐

  1. 【Linux 内核 内存管理】优化内存屏障 ④ ( 处理器内存屏障 | 八种处理器内存屏障 | 通用内存屏障 | 写内存屏障 | 读内存屏障 | 数据依赖屏障 | 强制性内存屏障 |SMP内存屏障 )

    文章目录 一.处理器内存屏障 二.Linux 内核处理器内存屏障 一.处理器内存屏障 " 处理器内存屏障 " 针对 " CPU " 之间的内存访问乱序 和 CP ...

  2. 【Linux 内核 内存管理】优化内存屏障 ② ( 内存屏障 | 编译器屏障 | 处理器内存屏障 | 内存映射 I/O 写屏障 )

    文章目录 一.内存屏障 二.编译器屏障 三.处理器内存屏障 一.内存屏障 内存屏障 , 又称为 " 屏障指令 " , 用于保证 " 编译器 " 或 " ...

  3. Linux并发与同步专题 (1)原子操作和内存屏障

    关键词:. <Linux并发与同步专题 (1)原子操作和内存屏障> <Linux并发与同步专题 (2)spinlock> <Linux并发与同步专题 (3) 信号量> ...

  4. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  5. 内核同步机制-RCU同步机制

    转自http://www.360doc.com/content/09/0805/00/36491_4675691.shtml 目录 [隐藏] 1 RCU同步机制 1.1 RCU介绍 1.2 RCU A ...

  6. 内核同步机制-读写信号量(rw_semaphore)

    四.读写信号量(rw_semaphore) 读/写信号量适于在读多写少的情况下使用.如果一个任务需要读和写操作时,它将被看作写者,在不需要写操作的情况下可降级为读者.任意多个读者可同时拥有一个读/写信 ...

  7. java内存屏障_java内存屏障

    java内存屏障 java的内存屏障通常所谓的四种即LoadLoad,StoreStore,LoadStore,StoreLoad实际上也是上述两种的组合,完成一系列的屏障和数据同步功能. LoadL ...

  8. linux 内存屏障,理解内存屏障(一)

    作者:新浪微博() 计算机学习微信公众号(jsj_xx) 1 前言 内存屏障是搞软件的需要面对的一个涉及硬件cpu的问题,很多人困惑不解.本文是我们对linux内核内存屏障的理解,参考linux内核( ...

  9. java内存屏障_内存屏障 | 并发编程网 – ifeve.com

    本文我将和大家讨论并发编程中最基础的一项技术:内存屏障或内存栅栏,也就是让一个CPU处理单元中的内存状态对其它处理单元可见的一项技术. CPU使用了很多优化技术来实现一个目标:CPU执行单元的速度要远 ...

最新文章

  1. for...in和for...of以及for( :)的区别
  2. birt脚本for循环语句_python循环语句(while amp; for)
  3. uniapp 如何配置MySQL_uniapp后台api设计(微信user表)
  4. php+tcpdf+表格,PHP使用tcpdf类生成PDF文件
  5. HB哈勃与HB公链【尊皇社区】深度揭秘分析!
  6. 【多目标追踪算法】多目标跟踪评价指标
  7. 点阵字库怎样才能做到字符显示更紧凑?
  8. python处理图片文件,python 间接处理webp图片文件
  9. 2019年最新目标检测算法综述汇总
  10. 【关于如何调用java的private成员变量】
  11. 2012年度江西省科学技术奖授奖项目名单
  12. python读parquet文件 pandas读parquet文件
  13. 2016年GitHub上史上最全的Android开源项目分类汇总
  14. Amazon SES 邮件发送服务
  15. 不要做联表查询!!!
  16. 图像分辨率、像素总数、文件大小之间的详细区别
  17. 假如你是QQ的产品经理
  18. 微信公众平台SDK! Senparc.Weixin.MP.dll(资料整理)
  19. 【HDU 5445】Food Problem(DP)
  20. DCDC直流转换器(自用版

热门文章

  1. cdr自动排版插件_CDR ymxkDoc插件 支持X72020到以后版本
  2. zookeeper注册中心 kerberos_ZooKeeper 并不适合做注册中心
  3. gitee项目能用SVN拉取吗_基于SpringBoot的车牌识别系统(附项目地址)
  4. 瑞芯微和全志哪个好_瑞芯微和全志科技基本面信息简要对比和整理
  5. 打算年后跳槽的注意了... 这个岗位,人才缺口30万 薪资水涨船高
  6. python sys模块 argv用法_python中sys模块的argv
  7. python中模块文件的扩展名不一定是py_python模块和python包有什么区别?
  8. java.io.serializable_java.io.NotSerializableException即使我实现“Serializable”
  9. 卷积神经网络创建模型
  10. Java改环境变量把path修改了,CentOS查看和修改PATH环境变量的方法