这一文,让我们分析一下,《浅谈 Cache》 一文中的奇怪现象,事实上如今来看也并不奇怪了。

        在什么情况下 r1 和 r2 都为 0 呢?

        细致看代码,你会发现,两个线程分别被执行在不同的 CPU 核上,而且在线程開始的阶段还使用了一个随机数,是为了让两个线程能尽量同一时候执行。

        如果 CPU0 执行:

        x = 1;

        r1 = y;

        CPU1 执行:

        y = 1;

        r2 = x;

        假设以下的情况发生:

        x 在 CPU1 的 Cache 中。 y 在 CPU0 的 Cache 中。

        1. CPU0 运行 x = 1, cache miss, 发送 "read invalidate" 消息,并把 x 的值 1 存入 Store Buffer, 開始运行 r1 = y, Cache 命中,r1 为 0;

        2. CPU1 运行 y = 1,cache miss, 发送 "read invalidate" 消息,并把 y 的值 1 存入 Store Buffer, 開始运行 r2 = x,Cache 命中,r2 为 0;

        3. CPU0 和 CPU1 各自收到了对方的消息,并作出回应,x 和 y 的值均应用到 Cache 中,且都为 1;

        主函数收到信号,比較 r1 和 r2 的值,奇迹发生了。

        假设你知道我讲的这些细节,就会发现,事实上这并非奇怪了。那么假设解决问题呢?

        事实上答案就非常easy了,要么让两个线程执行在同一个核心上,要么在两个语句之间加上内存屏障,经验证,问题攻克了。

        题外篇:

        在不同 CPU 架构下,对内存的乱序訪问事实上是不同的,一般的内存乱序分为下面四种:

        LoadStore, LoadLoad, StoreStore, StoreLoad。而且 X86 下仅仅会出现 StoreLoad 乱序,也就是上面的样例,我的 CPU 是 X86 的,所以出现了这样的情况,由此可知,事实上 X86 内存乱序訪问的还不算太厉害。

        简单解释一下,x = 1,为 Store, 读取 y 的过程为 Load,所以 Load 指令在 X86 下同意在 Store 还未更新到 Cache 中之前被运行。

        走出一个误区,内存乱序訪问与 CPU 乱序运行(Out of Order,即 OOO)不同。

早期的处理器为有序处理器(In-order processors),有序处理器处理指令通常有下面几步:

        1. 指令获取

2. 假设指令的输入操作对象(input operands)可用(比如已经在寄存器中了),则将此指令分发到适当的功能单元中。假设一个或者多个操作对象不可用(一般是因为须要从内存中获取),则处理器会等待直到它们可用;

3. 指令被适当的功能单元运行

4. 功能单元将结果写回寄存器堆(Register file,一个 CPU 中的一组寄存器)

 

        相比之下,乱序处理器(Out-of-order processors)处理指令通常有下面几步:

        1. 指令获取

        2. 指令被分发到指令队列

        3. 指令在指令队列中等待,直到输入操作对象可用(一旦输入操作对象可用,指令就能够离开队列,即便更早的指令未被运行)

        4. 指令被分配到适当的功能单元并运行

        5. 运行结果被放入队列(而不马上写入寄存器堆)

        仅仅有全部更早请求运行的指令的运行结果被写入寄存器堆后,指令运行的结果才被写入寄存器堆(运行结果重排序,让运行看起来是有序的)

        从上面的运行过程能够看出,乱序运行相比有序运行能够避免等待不可用的操作对象(有序运行的第二步)从而提高了效率。现代的机器上,处理器运行的速度比内存快非常多,有序处理器花在等待可用数据的时间里已经能够处理大量指令了。

        如今思考一下乱序处理器处理指令的过程,我们能得到几个结论:

        对于单个 CPU 指令获取是有序的(通过队列实现)

        对于单个 CPU 指令运行结果也是有序返回寄存器堆的(通过队列实现)

        由此可知,在单 CPU 上,不考虑编译器优化导致乱序的前提下,多线程运行不存在内存乱序訪问的问题

        CPU 尽管是乱序运行,可是是顺序流出结果,在我们看来,乱序运行对我们来讲是透明的,我们看到的结果和指令顺序是一样的。

Cache 总结的更多相关文章

  1. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

  2. [Java 缓存] Java Cache之 DCache的简单应用.

    前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...

  3. Spring cache简单使用guava cache

    Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...

  4. 笔记:Memory Notification: Library Cache Object loaded into SGA

    笔记:Memory Notification: Library Cache Object loaded into SGA在警告日志中发现一些这样的警告信息:Mon Nov 21 14:24:22 20 ...

  5. ABP源码分析十三:缓存Cache实现

    ABP中有两种cache的实现方式:MemroyCache 和 RedisCache. 如下图,两者都继承至ICache接口(准确说是CacheBase抽象类).ABP核心模块封装了MemroyCac ...

  6. [Java 缓存] Java Cache之 Guava Cache的简单应用.

    前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(40)-精准在线人数统计实现-【过滤器+Cache】

    系列目录 上次的探讨没有任何结果,我浏览了大量的文章和个别系统的参考!决定用Cache来做,这可能有点难以接受但是配合mvc过滤器来做效果非常好! 由于之前的过滤器我们用过了OnActionExecu ...

  8. HTML5离线缓存(Application Cache)

    HTML5离线缓存又名Application Cache,是从浏览器的缓存中分出来的一块缓存区,要想在这个缓存中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源. ...

  9. 第三篇 Entity Framework Plus 之 Query Cache

    离上一篇博客,快一周,工作太忙,只能利用休息日来写一些跟大家分享,Entity Framework Plus 组件系列文章,之前已经写过两篇 第一篇 Entity Framework Plus 之 A ...

  10. HTML5应用程序缓存Application Cache

    什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...

随机推荐

  1. 使用 Polyfill 而不再是 bable 来实践js新特性

    现状 我们想要用ES6 语法来写 JavaScript.然而由于我们需要兼容老版本的浏览器,那些浏览器不支持 ES6,我们需要解决这个问题. 有一个标准的做法是:写 ES6 代码 → 将所有代码编译成 ...

  2. 引入外部CSS的两种方式及区别

    1.CSS的两种引入方式 通过@import指令引入 @import指令是CSS语言的一部分,使用时把这个指令添加到HTML的一个<style>标签中: 要与外部的CSS文件关联起来,得使 ...

  3. CodeForces A. Meeting of Old Friends

    2019-05-30 20:19:57 加油!!! sort(a + 1, a + 5); 卡了一会儿 #include <bits/stdc++.h> using namespace s ...

  4. Win10重置 系统诸多设置或者菜单点击无效或者异常信息回复办法

    cmd: 输入下列脚本重新注册DLL文件,待执行完毕后重启电脑 for %1 in (%windir%\system32\*.dll) do regsvr32.exe /s %1

  5. 缓存,队列(Redis,RabbitMQ)

    Redis Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...

  6. 4.Flask-alembic数据迁移工具

    alembic是用来做ORM模型与数据库的迁移与映射.alembic使用方式跟git有点类似,表现在两个方面,第一个,alemibi的所有命令都是以alembic开头: 第二,alembic的迁移文件 ...

  7. UOJ 129/BZOJ 4197 寿司晚宴 状压DP

    //By SiriusRen #include <cstdio> #include <algorithm> using namespace std; ; struct Node ...

  8. IIS7部署网站的一些细节问题。

    1.不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况. 这个错误的原因是在 IIS 7中 采用了更安全的 web.config 管理机制,默认情况下会锁住配置项.要取消锁定可以以 ...

  9. MOOC推荐及三门基础学科

    top1:学堂在线 http://www.xuetangx.com/ top2:网易云课堂 http://study.163.com/ top3:coursera https://www.course ...

  10. webapi部署到IIS 404错误

    环境:win2008r2+IIS 解决方案: 添加一个映射 可执行文件地址(根据系统决定64位可32位): C:\Windows\Microsoft.NET\Framework64\v4.0.3031 ...