这回该进入主题了。

        上一文最后提到了 Memory Barriers ,即内存屏障。由于对一个 CPU 而言,a = 1; b = 1. 由于在中间加了内存屏障,在 X86 架构下,就是 mfence 指令,此时在上一文中执行时。情况就变成这样了,当 CPU0 发

出 "read invalidate" 消息后,就会開始运行 mfence 指令,该指令把 Store Buffer 中的项都标记一下。然后開始运行 b = 1,此时尽管 cache hint (cache 命中),可是因为 Store Buffer 中存在被标记的项,所以

b 的新值不会直接应用到 cache 中,它也会被记录到 Store Buffer 中,并会等待被 Store Buffer 中被标记的项被应用,CPU0 也会继续运行其他指令。

        这样 CPU1 将会看到正确的 a 的值。看似完美的结局。事实上还差那么一点点。

        依旧是上一文的小样例。

a 和 b 初始化都为 0。 a 在 CPU1 的 cache 中, b 在 CPU0 的 cache 中。

        CPU 0 运行以下的代码:

        a = 1;

mfence;

        b = 1;

        CPU1 运行以下的代码:

        while (b != 1);

        assert (a == 1);

        断言一定能成功吗? 让我们如果以下的情况发生:

        1. CPU0 运行 a = 1, 可是发现 a 不在 cache 中。它就发出 "read invalidate" 消息,而且把 a 的值存在 store buffer 中;

        2。

CPU1 运行 b != 1 的比較,读取 b 的值,结果不在 cache 中,由于它不想改写,所以仅仅发一个 "read" 消息出去。

        3. CPU0 运行 mfence, 将 Store Buffer 中的项所有标记,然后运行 b = 1, 结果发现 Store Buffer 中有标记的项,所以就把 b 的值也记录在 Store Buffer,这些项是未标记的。

        4. CPU1 收到 "read invalidate" 消息,它把这个消息存入 Invalidate Queue 中。并作出回应;

        5. CPU0 收到回应,把 a 的值写入 Cache line, 把 b 的值也写入 cache line; 

        6. CPU0 收到 "read" 消息,并用出回应;

        7. CPU1 收到回应,退出循环,此时读取 a 的值,因为 Invalidate 消息还在队列中。此时它会觉得 Cache line 中 a 的值有效,但事实上为旧值,所以断言错误。

        非常明显。兵败在了 Invalidate Queue 上。那可不能够向 Store Buffer 一样。弄一个屏障在读取 Cache line 时作一下检查呢?

        假设你能想到这里,说明赶上了设计 CPU 的那些家伙。对,这里也能够用一个 mfence.

        代码就成了这个样子

        while (b != 1);

        mfence;

        assert(a == 1);

        这样当 while (b != 1) 退出循环之后,遇到了 mfence, 它就必须停下来把 Message Queue 中的所以消息应用到 Cache line 中,此时就会发现 a 的 cache line 失效。当再进行读取 a 时,就会发消息给

CPU0 。进而得到正确的结果。

事实上 X86 提供细粒度的指令 lfence (读屏障), sfence (写屏障)。 mfence(读写屏障)。

lfence: 该指令把当前invalidate queue 里的所有项标记。当 load 动作发生时,假设队列中有标记项。那么 CPU 必须把 Message Queue 中存在的消息所有应用之后,才会运行后面的指令。

这样读取就变得安全;

        sfence: 该指令把标记 Store Buffer 中所以已存在的写入记录项。当下次再有写入操作时,即使命中也不会直接应用到 cache 中。而是记录到 Store Buffer 中。

        mfence: 兼备以上两条指令的作用。

        另一些其他指令具备这种作用,一般如带 lock 前缀的指令等。

所以普通情况下内存屏障须要成对使用。

        最终快要完了。

Memory Barriers的更多相关文章

  1. 内存级别/栅栏 ( Memory Barriers / Fences ) – 翻译

    翻译自:Martin Thompson – Memory Barriers/Fences 在这篇文章里,我将讨论并发编程里最基础的技术–以内存关卡或栅栏著称.那让进程内的内存状态对其它进程可见. CP ...

  2. Synthesis of memory barriers

    A framework is provided for automatic inference of memory fences in concurrent programs. A method is ...

  3. Memory Barriers Are Like Source Control Operations

    From:   http://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ If you use ...

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

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

  5. Memory Barriers ,cache-coherency

    http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf Shared-Memory Synchroniza ...

  6. Linux内核同步机制之(三):memory barrier【转】

    转自:http://www.wowotech.net/kernel_synchronization/memory-barrier.html 一.前言 我记得以前上学的时候大家经常说的一个词汇叫做所见即 ...

  7. Linux内核同步 - memory barrier

    一.前言 我记得以前上学的时候大家经常说的一个词汇叫做所见即所得,有些编程工具是所见即所得的,给程序员带来极大的方便.对于一个c程序员,我们的编写的代码能所见即所得吗?我们看到的c程序的逻辑是否就是最 ...

  8. Memory Ordering in Modern Microprocessors

    Linux has supported a large number of SMP systems based on a variety of CPUs since the 2.0 kernel. L ...

  9. memory ordering 内存排序

    Memory ordering - Wikipedia https://en.wikipedia.org/wiki/Memory_ordering https://zh.wikipedia.org/w ...

随机推荐

  1. [ Python - 13 ] 批量管理主机必备模块

    批量管理程序必备模块 optparse configparser paramiko optparse模块 简介:        optparse模块主要用来为脚本传递命令参数功能 使用步骤: 1. i ...

  2. w3cschool javascript学习

    name与Id属性区别 1.我们知道在网页做Post提交时,是以Form(即表单域)为单位进行提交的,一个Form里有若干个表单对象(如<input type="text" ...

  3. hdu5829

    多校训练8,有官方题解 主要之前没写过ntt,感觉不是很懂原根 先贴一份当模板吧 #include<iostream> #include<cstdio> #include< ...

  4. React Native - 3 View, Text简介以及onPress & onLongPress事件

    我们要生成如下的构图   直接上图,不解释.       如下图所示,定义函数,函数之间不需要逗号,在元素上添加事件,使用关键字this.{function name}    

  5. STL模板整理 set

    SET set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序.应该注意的是set中数元素的值不能直接被 ...

  6. php中parse_url函数的源码及分析

    前言 看师傅们的文章时发现,parse_url出现的次数较多,单纯parse_url解析漏洞的考题也有很多,在此研究一下源码(太菜了看不懂,待日后再补充Orz) 源码 PHPAPI php_url * ...

  7. 训练指南 UVA - 11383(KM算法的应用 lx+ly >=w(x,y))

    layout: post title: 训练指南 UVA - 11383(KM算法的应用 lx+ly >=w(x,y)) author: "luowentaoaa" cata ...

  8. 【Heap-Dijkstra】【分层图】bzoj2763 [JLOI2011]飞行路线

    建立k+1张图, 在图与图之间,若在原图中x到y有边,就建立从 第i层的x 到 i+1层的y 建边,权值为0.代表一次免费机会. 由于一旦到了第i+1层的图里,则无法回到之前的层,所以免费最多只有k次 ...

  9. 【前缀和】【前缀MAX】洛谷 P1351 NOIP2014提高组 day1 T2 联合权值

    不难发现,树中与某个点距离为2的点只可能是它的父亲的父亲.儿子的儿子 或者 兄弟,分类讨论一下即可. 只有对于兄弟我们不能暴力搞,维护一下每个节点的所有儿子的前缀和.前缀MAX就行了. #includ ...

  10. [TC-HouseProtection]House Protection

    题目大意: 一个平面直角坐标系中有给定的$n(n\le50)$个红点和$m(m\le50)$个蓝点,每个点可以选择画一个半径为$r$(所有的$r$相同)的圆或不画.圆的半径上限为$R(R\le1000 ...