内存屏障 & 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。

时间: 2024-10-06 23:31:26

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

技术向|内存屏障(Memory Barriers)--Runtime Time

在讨论CPU的内存屏障之前,让我们先了解一下缓存结构. 缓存(Cache)结构简介 现代计算机系统的缓存结构粗略如下: 每个CPU都有自己的缓存. 缓存(Cache)分为又分多个级别. 一级缓存L1的访问非常接近一个cpu周期(cycles),二级缓存L2的存取可能就要大概10个周期了. 缓存和内存交换数据的最小单元叫Cache Line.它是一个固定长度的块,可能是16到256字节(bytes). 比如一个32位的CPU有1M的缓存,每个Cache Line的大小是64bytes.那么这个缓存

原子操作&优化和内存屏障

原子操作 假定运行在两个CPU上的两个内核控制路径试图执行非原子操作同时"读-修改-写"同一存储器单元.首先,两个CPU都试图读同一单元,但是存储器仲裁器插手,只允许其中的一个访问而让另一个延迟.然而,当第一个读操作已经完成后,延迟的CPU从那个存储器单元正好读到同一个(旧)值.然后,两个CPU都试图向那个存储器单元写一新值,总线存储器访问再一次被存储器仲裁器串行化,最终,两个写操作都成功.但是,全局的结果是不对的,因为两个CPU写入同一(新)值.因此,两个交错的"读-修改-

Linux内核中的内存屏障解析

缓存一致性 之前一直认为linux中很多东西是用来保证缓存一致性的,其实不是.缓存一致性绝大部分是靠硬件机制实现的,只有在带lock前缀的指令执行时才与cache有一点关系.(这话说得绝对,但我目前看来就是这样)我们更多的时候是为了保证顺序一致性. 所谓缓存一致性,就是在多处理器系统中,每个cpu都有自己的L1 cache.很可能两个不同cpu的L1 cache中缓存的是同一片内存的内容,如果一个cpu更改了自己被缓存的内容,它要保证另一个cpu读这块数据时也要读到这个最新的.不过你不要担心,这

聊聊高并发(三十五)理解内存屏障

在聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了硬件层提供了满足某些一致性需求的能力,Java内存模型利用了硬件层提供的能力指定了一系列的语法和规则,让Java开发者可以隔绝这种底层的实现专注于并发逻辑的开发.这篇我们来看看硬件层是如何提供这些实现一致性需求的能力的. 硬件层提供了一系列的内存屏障 memory barrier / memory fence(Intel的提法)来提供一致性的能力.拿X86平台来说,有几种主要的内存屏障 1. ifence

memory barrier 内存栅栏 并发编程

并发编程 memory barrier (内存栅栏) CPU级 1.CPU中有多条流水线,执行代码时,会并行进行执行代码,所以CPU需要把程序指令 分配给每个流水线去分别执行,这个就是乱序执行: 2.CPU中有read buffer/ write buffer 这2个读写缓存,这2个部件用于缓存CPU对内存的读写操作,并不是实时同步到CPU缓存(L1/L2/L3),这个就会导致更新一块内存后,其他CPU感知不到: 读取的时候,优先到read buffer找数据,找到了,就用这个数据了,如果这时内

并行计算之Memory barrier(内存

本文转载自:http://name5566.com/4535.html 参考文献列表:http://en.wikipedia.org/wiki/Memory_barrierhttp://en.wikipedia.org/wiki/Out-of-order_executionhttps://www.kernel.org/doc/Documentation/memory-barriers.txt 本文例子均在 Linux(g++)下验证通过,CPU 为 X86-64 处理器架构.所有罗列的 Linu

LINUX内核内存屏障

================= ================= By: David Howells <[email protected]> Paul E. McKenney <[email protected]> 译: kouu <[email protected]> 出处: Linux内核文档 -- Documentation/memory-barriers.txt 文件夹: (*) 内存訪问抽象模型. - 操作设备. - 保证. (*) 什么是内存屏障? -

大话Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁

大话Linux内核中锁机制之内存屏障.读写自旋锁及顺序锁 在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔者讨论自旋锁的禁止或使能的时候,提到过一个内存屏障函数.OK,接下来,笔者将讨论内存屏障的具体细节内容.我们首先来看下它的概念,Memory Barrier是指编译器和处理器对代码进行优化(对读写指令进行重新排序)后,导致对内存的写入操作不能

线程同步(1):原子操作,内存屏障,锁综述

原子操作,内存屏障,锁 1.原理:CPU提供了原子操作.关中断.锁内存总线,内存屏障等机制:OS基于这几个CPU硬件机制,就能够实现锁:再基于锁,就能够实现各种各样的同步机制(信号量.消息.Barrier等等等等). 2.所有的同步操作最基础的理论就是原子操作.内存屏障,锁都是为了保证在不同的平台或者是CPU类型下的原子操作. 3.原子操作在单核,单线程/无中断,且编译器不优化的情况下是确定的,是按照C/C++代码顺序执行的,所以不存在异步问题 解释一下这几个知识点为什么会引起异步操作: 首先了