Memory Barrier

http://www.wowotech.net/kernel_synchronization/memory-barrier.html

这里面讲了Memory Barrier

对于一个c程序员,我们的编写的代码能所见即所得吗?我们看到的c程序的逻辑是否就是最后CPU运行的结果呢?很遗憾,不是,我们的“所见”和最后的执行结果隔着:

1、编译器

2、CPU取指执行

编译器了解底层CPU的思维模式,因此,它可以在将c翻译成汇编的时候进行优化(例如内存访问指令的重新排序),让产出的汇编指令在CPU上运行的时候更快。然而,这种优化产出的结果未必符合程序员原始的逻辑,因此,作为程序员,作为c程序员,必须有能力了解编译器的行为,并在通过内嵌在c代码中的memory barrier来指导编译器的优化行为(这种memory barrier又叫做优化屏障,Optimization barrier),让编译器产出即高效,又逻辑正确的代码。

我们先看下面的一个例子:

preempt_disable()

临界区

preempt_enable

我们知道所谓的preempt enable和disable其实就是对当前进程的struct thread_info中的preempt_count进行加一和减一的操作。具体的代码如下:

#define preempt_disable() \ 
do { \ 
    preempt_count_inc(); \ 
    barrier(); \ 
} while (0)

使用do...while(0)的好处可见:

http://www.cnblogs.com/charlesblc/p/6080315.html

linux kernel中的定义和我们的想像一样,除了barrier这个优化屏障。barrier就象是c代码中的一个栅栏,将代码逻辑分成两段,barrier之前的代码和barrier之后的代码在经过编译器编译后顺序不能乱掉。也就是说,barrier之后的c代码对应的汇编,不能跑到barrier之前去,反之亦然。之所以这么做是因为在我们这个场景中,如果编译为了榨取CPU的performace而对汇编指令进行重排,那么临界区的代码就有可能位于preempt_count_inc之外,从而起不到保护作用。

barrier是否够呢?

对于multi-core的系统,只有当该task被调度到该CPU上执行的时候,该CPU才会访问该task的preempt count,因此对于preempt enable和disable而言,不存在多个CPU同时访问的场景。

但是,即便这样,如果CPU是乱序执行(out-of-order excution)的呢?其实,我们也不用担心,正如前面叙述的,preempt count这个memory实际上是不存在多个cpu同时访问的情况,因此,它实际上会本cpu的进程上下文和中断上下文访问。能终止当前thread执行preempt_disable的只有中断。为了方便描述,我们给代码编址,如下:

地址 该地址的汇编指令 CPU的执行顺序
a preempt_disable() 临界区指令1
a+4 临界区指令1 preempt_disable()
a+8 临界区指令2 临界区指令2
a+12 preempt_enable preempt_enable

当发生中断的时候,硬件会获取当前PC值,并精确的得到了发生指令的地址。有两种情况:

(1)在地址a发生中断。对于out-of-order的CPU,临界区指令1已经执行完毕,preempt_disable正在pipeline中等待执行。由于是在a地址发生中断,也就是preempt_disable地址上发生中断,对于硬件而言,它会保证a地址之前(包括a地址)的指令都被执行完毕,并且a地址之后的指令都没有执行。因此,在这种情况下,临界区指令1的执行结果被抛弃掉,因此,实际临界区指令不会先于preempt_disable执行

(2)在地址a+4发生中断。这时候,虽然发生中断的那一刻的地址上的指令(临界区指令1)已经执行完毕了,但是硬件会保证地址a+4之前的所有的指令都执行完毕,因此,实际上CPU会执行完preempt_disable,然后跳转的中断异常向量执行。

注意:如果CPU是乱序执行(out-of-order excution)的,barrier只是保证compiler输出的汇编指令的顺序是OK的,不能确保CPU执行时候的乱序。

CPU会乱排,但是有的顺序不会调换,根据load和store型指令,不同处理器的策略不同,可以见:

Java内存模型(可以结合着看)

http://www.cnblogs.com/charlesblc/p/6126551.html

对这个问题的回答来自ARM architecture的内存访问模型:对于program order是A1-->A2的情况(A1和A2都是对Device或是Strongly-ordered的memory进行访问的指令),ARM保证A1也是先于A2执行的。因此,在这样的场景下,使用barrier足够了。 对于X86也是类似的,虽然它没有对IO space采样memory mapping的方式,但是,X86的所有操作IO端口的指令都是被顺执行的,不需要考虑memory access order。

内存屏障 & Memory barrier的更多相关文章

  1. 高速缓存一致性协议MESI与内存屏障

    一.CPU高速缓存简单介绍 CPU高速缓存机制的引入,主要是为了解决CPU越来越快的运行速度与相对较慢的主存访问速度的矛盾.CPU中的寄存器数量有限,在执行内存寻址指令时,经常需要从内存中读取指令所需 ...

  2. java内存屏障

    为什么会有内存屏障 每个CPU都会有自己的缓存(有的甚至L1,L2,L3),缓存的目的就是为了提高性能,避免每次都要向内存取.但是这样的弊端也很明显:不能实时的和内存发生信息交换,分在不同CPU执行的 ...

  3. JMM中的重排序及内存屏障

    目录 1. 概述 2. 重排序 2-1. as-if-serial语义 2-2. 重排序的种类 2-3. 从Java源代码到最终实际执行的指令序列, 会分别经历下面3中重排序. 3. 内存屏障类型 3 ...

  4. memory barrier 内存屏障 编译器导致的乱序

    小结: 1. 很多时候,编译器和 CPU 引起内存乱序访问不会带来什么问题,但一些特殊情况下,程序逻辑的正确性依赖于内存访问顺序,这时候内存乱序访问会带来逻辑上的错误, 2. https://gith ...

  5. 内存屏障(Memory barrier)-- 转发

    本文例子均在 Linux(g++)下验证通过,CPU 为 X86-64 处理器架构.所有罗列的 Linux 内核代码也均在(或只在)X86-64 下有效. 本文首先通过范例(以及内核代码)来解释 Me ...

  6. 理解 Memory barrier(内存屏障)无锁环形队列

    原文:https://www.cnblogs.com/my_life/articles/5220172.html Memory barrier 简介 程序在运行时内存实际的访问顺序和程序代码编写的访问 ...

  7. 理解 Memory barrier(内存屏障)【转】

    转自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wikiped ...

  8. 什么是内存屏障? Why Memory Barriers ?

           要了解如何使用memory barrier,最好的方法是明白它为什么存在.CPU硬件设计为了提高指令的执行速度,增设了两个缓冲区(store buffer, invalidate que ...

  9. 并行计算之Memory barrier(内存

    本文转载自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wiki ...

随机推荐

  1. 【皇甫】☀初识AOP

    新知识,新起点,下面介绍一下aop所要准备架包和各个层 特点: 创建好的各个层: 所需架包: 具体步骤: No.1  搭建分层架构 entity 1 public class User impleme ...

  2. 【皇甫】☀Spring开题中...

    spring (由Rod Johnson创建的一个开源框架)Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建.简单来说,Spr ...

  3. unrar.dll 使用实例

    /* * main.cpp * * Created on: Aug 17, 2015 * Author: smallcroco * * Discription: * 1 首先打开解压包,可以设置打开方 ...

  4. Java 获取两个日期之间的日期

    1.前期需求,两个日期,我们叫他startDate和endDate,然后获取到两个日期之间的日期 /** * 获取两个日期之间的日期 * @param start 开始日期 * @param end ...

  5. html5,增加flash插件

    <embed src="2.swf" type="" width="500" height="" >< ...

  6. dd-wrt 定时重连 pppoe 更换ip地址

    因为做代理,IP时常被封的原因,所以,需要每天定时重启路由器,重启路由器影响太大,所以重新拨号是一个更好的选择. 在dd-wrt里面,杀掉pppoe服务进程就可以了,这个进程会自动重新启动,然后就相当 ...

  7. Infinite loop when using cookieless session ID on Azure

    If you use cookieless session ID and deploy them on Azure, you might get infinite loop when you quer ...

  8. 省市联动sql脚本

    create database ProCityData use Procitydata --创建Province(省表) create table Province ( ProID int prima ...

  9. java socket 多线程通讯 使用mina作为服务端

    客户端代码不变,参照 http://www.cnblogs.com/Westfalen/p/6251473.html 服务端代码如下: import java.io.IOException; impo ...

  10. YUV格式分析

    转自:http://www.cnblogs.com/armlinux/archive/2012/02/15/2396763.html Andrew Huang <bluedrum@163.com ...