内存屏障

来源:互联网 发布:软件维保费用标准 编辑:程序博客网 时间:2024/04/28 16:29

        严格来讲,内存屏蔽不止仅限于 Linux Kernel 范畴,其实 Windows 中也有这个概念,只不过在编写 Linux Kernel 时对于这个概念会经常的遇到,所以暂归此类。

        Barrier (Optimization barrier)像立在代码中的一堵墙,前面的代码不能重排到后面,后面的代码不能重排到前面,当然,受约束的前提是这些代码都是依赖内存的。”memory ” 就是告知内存被修改了,依赖内存的变量在之后都将被重读,除非对应内存是只读的,否则任何访存指令都会添加内存依赖。加上volatile修饰符可以防止对其进行优化,因为Optimization barrier是一个空语句,如果不加上volatile,编译器可能会过激优化,将其删除。屏障之前,所有在寄存器中的结果要写回内存;屏障之后,数据需要重新从内存中加载,其实这一点很像一个全局的volatile读写语义。

        引申:编译器的指令重排和内存缓存可以加快cpu 执行指令(为流水作业并行尽量铺平道路,让这些工作在编译期就努力创造条件)和内存访问(寄存器缓存)的速度,对于没有依赖关系的指令是有非常大的优化的,但是在端口操作过程中,有一些隐式的依赖,比如只有当上一个寄存器指令数据全部存取完成后,再向端口写数据才会生效,像这样的依赖,编译器的优化可能会给我们造成困扰,这个时候就需要对 cpu 硬件来控制屏障来保证在屏障以后,以前的指令读写的情况了。

        在 CPU 实现中,在序列正常的情况下,读和写的先后顺序是由 CPU 来保证的,后面的读写指令必然会在前面的读写指令完成后才完成。但在 smp 架构下,cache 的同步是异步的,需要使用屏障来保证 cache line 同步消息发出的顺序,以此类推,在接收 cpu 上即使接收和 cache 同步消息是顺序到来,处理更新的电路完成时间也是存在差异的,有可能后到的消息先同步完成,要想保证数据全部同步好,就要使用读屏障,来保证在屏障之前所有的读操作完成,当然就包括了 cache line 的更新工作,这也相当于读操作的一部分。

        I/O 设备的乱序,是因为虽然cpu 保证了写入内存(映射内存)的顺序,但有可能 I/O 控制器比较随意,当数据或状态寄存器的值还未真正初始好时,后到的控制寄存器的值就已经可用,并且 I/O 控制器就随意地认为可以执行了,造成错误,此时,应该由 I/O 控制器提供屏障来保证之前的动作已经完成,再进行屏障后的动作。

0 0