内存屏障 & Memory barrier
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的更多相关文章
- 高速缓存一致性协议MESI与内存屏障
一.CPU高速缓存简单介绍 CPU高速缓存机制的引入,主要是为了解决CPU越来越快的运行速度与相对较慢的主存访问速度的矛盾.CPU中的寄存器数量有限,在执行内存寻址指令时,经常需要从内存中读取指令所需 ...
- java内存屏障
为什么会有内存屏障 每个CPU都会有自己的缓存(有的甚至L1,L2,L3),缓存的目的就是为了提高性能,避免每次都要向内存取.但是这样的弊端也很明显:不能实时的和内存发生信息交换,分在不同CPU执行的 ...
- JMM中的重排序及内存屏障
目录 1. 概述 2. 重排序 2-1. as-if-serial语义 2-2. 重排序的种类 2-3. 从Java源代码到最终实际执行的指令序列, 会分别经历下面3中重排序. 3. 内存屏障类型 3 ...
- memory barrier 内存屏障 编译器导致的乱序
小结: 1. 很多时候,编译器和 CPU 引起内存乱序访问不会带来什么问题,但一些特殊情况下,程序逻辑的正确性依赖于内存访问顺序,这时候内存乱序访问会带来逻辑上的错误, 2. https://gith ...
- 内存屏障(Memory barrier)-- 转发
本文例子均在 Linux(g++)下验证通过,CPU 为 X86-64 处理器架构.所有罗列的 Linux 内核代码也均在(或只在)X86-64 下有效. 本文首先通过范例(以及内核代码)来解释 Me ...
- 理解 Memory barrier(内存屏障)无锁环形队列
原文:https://www.cnblogs.com/my_life/articles/5220172.html Memory barrier 简介 程序在运行时内存实际的访问顺序和程序代码编写的访问 ...
- 理解 Memory barrier(内存屏障)【转】
转自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wikiped ...
- 什么是内存屏障? Why Memory Barriers ?
要了解如何使用memory barrier,最好的方法是明白它为什么存在.CPU硬件设计为了提高指令的执行速度,增设了两个缓冲区(store buffer, invalidate que ...
- 并行计算之Memory barrier(内存
本文转载自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wiki ...
随机推荐
- 【皇甫】☀初识AOP
新知识,新起点,下面介绍一下aop所要准备架包和各个层 特点: 创建好的各个层: 所需架包: 具体步骤: No.1 搭建分层架构 entity 1 public class User impleme ...
- 【皇甫】☀Spring开题中...
spring (由Rod Johnson创建的一个开源框架)Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建.简单来说,Spr ...
- unrar.dll 使用实例
/* * main.cpp * * Created on: Aug 17, 2015 * Author: smallcroco * * Discription: * 1 首先打开解压包,可以设置打开方 ...
- Java 获取两个日期之间的日期
1.前期需求,两个日期,我们叫他startDate和endDate,然后获取到两个日期之间的日期 /** * 获取两个日期之间的日期 * @param start 开始日期 * @param end ...
- html5,增加flash插件
<embed src="2.swf" type="" width="500" height="" >< ...
- dd-wrt 定时重连 pppoe 更换ip地址
因为做代理,IP时常被封的原因,所以,需要每天定时重启路由器,重启路由器影响太大,所以重新拨号是一个更好的选择. 在dd-wrt里面,杀掉pppoe服务进程就可以了,这个进程会自动重新启动,然后就相当 ...
- 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 ...
- 省市联动sql脚本
create database ProCityData use Procitydata --创建Province(省表) create table Province ( ProID int prima ...
- java socket 多线程通讯 使用mina作为服务端
客户端代码不变,参照 http://www.cnblogs.com/Westfalen/p/6251473.html 服务端代码如下: import java.io.IOException; impo ...
- YUV格式分析
转自:http://www.cnblogs.com/armlinux/archive/2012/02/15/2396763.html Andrew Huang <bluedrum@163.com ...