这回该进入主题了。

        上一文最后提到了 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. 区块链开发(五)git、truffle安装

    truffle是以太坊最受欢迎的一个开发框架,本篇博客介绍truffle的下载安装过程. git安装 在安装truffle之前需要核实一下本机是否安装git程序.后面的程序安装需要依赖git. 输入以 ...

  2. hdu 5186(模拟)

    zhx's submissions Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  3. Linux下安装Sybase ASE 16

    https://jingyan.baidu.com/article/414eccf67281a16b421f0a76.html

  4. hdu5076

    好题,首先观察可得w[i][j]选择只有可能两种,一种比阀值大,一种比阀值小 比阀值大就一定选满足条件最大的w,比阀值小同样一定选满足条件最大的w 那么一个最小割模型就呼之欲出了,注意w可能是负数那么 ...

  5. 求给出第 K个 N位二进制数,该二进制数不得有相邻的“1”

    求给出第 K (0 < K < 109) 个 N (0 < N < 44) 位二进制数,该二进制数不得有相邻的"1". 这道题要求给出第 K (0 < ...

  6. 字典树(Trie Tree)

    终于要开始更新我的ACM学习之路了,不过没想到却是因为一次Java大作业,有趣,%yuan老师. 字典树是一种很简单的树形结构,主要用来进行词频统计,在算法竞赛中有时也会碰到. 字典树的基本思路是,通 ...

  7. 37、Django实战第37天:404以及500页面配置

    1.把404.html,500.html复制到templates下,替换静态文件路径 2.编辑users.views.py定义404,505函数 from django.shortcuts impor ...

  8. [BZOJ1559]密码

    数据范围特别小,考虑状压DP 因为要求给定的字符串在母串中出现,所以可以用AC自动机辅助DP 因为AC自动机不能处理模式串互相包含的情况,所以先把互相包含的串去掉(暴力就行,数据范围太小) 因为要状压 ...

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

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

  10. 【数论】【枚举约数】【欧拉函数】bzoj2705 [SDOI2012]Longge的问题

    ∵∑gcd(i, N)(1<=i <=N) =k1*s(f1)+k2*s(k2)+...+km*s(km) {ki是N的约数,s(ki)是满足gcd(x,N)=ki(1<=x< ...