这回该进入主题了。

        上一文最后提到了 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. 查找(二分、hash、桶)

    先上一个最简单的题 1230 元素查找 给出n个正整数,然后有m个询问,每个询问一个整数,询问该整数是否在n个正整数中出现过. 输入描述 Input Description 第一行两个整数 n 和m. ...

  2. flask学习:如何从config里载入配置

    代码如下: 1.main.py from flask import Flask from config import DevConfig app=Flask(__name__) app.config. ...

  3. swipper插件引起的a链接失效问题

    在使用swiper过程中,发现a链接失效,此处没有效果,问题是 swiper是基于移动端触摸的,会有一个全局的click事件,这个事件屏蔽了A标签的链接,是为了防止手机滑动的时候不小心触发A标签而设定 ...

  4. codeforces Round #440 A Search for Pretty Integers【hash/排序】

    A. Search for Pretty Integers [题目链接]:http://codeforces.com/contest/872/problem/A time limit per test ...

  5. HDU 1060 Leftmost Digit (数论,快速幂)

    Given a positive integer N, you should output the leftmost digit of N^N.  InputThe input contains se ...

  6. ASP.NET Core 2.2 基础知识(十七) SignalR 一个极其简陋的聊天室

    这是一个极其简陋的聊天室! 这个例子只是在官方的例子上加了 Group 的用法而已,主要是官方给的 Group 的例子就两行代码,看不出效果. 第一步:修改 chat.js "use str ...

  7. Verify Preorder Serialization of a Binary Tree -- LeetCode

    One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, ...

  8. [LOJ#2540][PKUWC2018]随机算法(概率DP)

    场上数据很水,比较暴力的做法都可以过90分以上,下面说几个做法. 1. 暴力枚举所有最大独立集,对每个独立集分别DP.复杂度玄学,但是由于最大独立集并不多,所以可以拿90. 2. dp[S][k]表示 ...

  9. [CF986E]Prince's Problem

    题意:给一棵带点权$w_i$的树,多次询问$(u,v,x)$,求出$\prod\limits_{i\in\text{path}(u,v)}(w_i,x)$ 因为是乘法,所以可以把路径询问拆成到根询问, ...

  10. 显示图案 Exercise06_06

    import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:显示图案 * 输入一个数 5 1 2 1 3 2 1 4 3 2 1 5 ...