从硬件级别再看可见性和有序性

前言

王子之前的文章对于并发编程中的可见性问题已经有了一个初步的介绍,总结出来就是CPU的缓存会导致可见性问题

这样的解释其实是没有问题的,但这里说的“缓存”其实一个笼统的概念,缓存其实指的是寄存器、高速缓存和写缓冲器

今天我们就从硬件的级别再来探索一下出现可见性问题的原因,让小伙伴们有一个更深的认识。

同时再深入探索一下有序性问题的产生原因。

如果小伙伴们对于寄存器、高速缓存、缓冲器、总线的概念还不清楚,建议自行去查阅资料了解。

出现可见性问题的原因

首先,我们知道每个CPU都有自己的寄存器,它用于存储临时的二进制数据,做一些数据运算。

所以当多个CPU各自运行一个线程的时候,就会导致在寄存器中对数据的修改对其他CPU是不可见的。

然后,一个CPU对变量的写操作都是针对写缓冲器的,并不是直接把值写到主内存中。

所以没有写到主内存中的数据,对其他CPU是不可见的。

然后写入缓冲器后,会把更新后的数据写入到高速缓存中,之后把变量更新信息通过总线通知给其他CPU,但是其他CPU可能会认为这个更新是无效的,不会更新它自己的高速缓存数据,这就导致了高速缓存的可见性问题。

整体的内存模型如图:

MESI协议解决可见性

解决可见性问题的一种方案就是MESI协议,这个MESI协议,根据不同的硬件系统,会有不同的实现方式。

比如MESI的一种实现方式,就是CPU接收到变量更新的消息后,直接更新数据到自己的高速缓存中,这样各个CPU高速缓存中的数据就一致了,解决了可见性问题。

说到MESI协议,王子要跟大家说两个新名词,flush和refresh。

先来说一下flush。

flush就是把自己更新的值刷新到高速缓存(或主内存)中,除了flush操作,同时还会发送一个消息到总线(bus),通知其他处理器某个变量值被修改了。

那refresh又是什么呢?

refresh指的是,处理器中的线程在读取某个变量的时候,如果发现其他处理器的线程修改了这个变量,那就必须过期掉自己高速缓存中的值,从其他处理器的高速缓存(或主内存)中读取变量,同步到自己的高速缓存中。

这就是MESI协议最最基础的原理。

探索有序性问题

之前的文章我们已经说过,指令重排会导致有序性问题,那么具体什么时候会发生指令重排呢?这就要从代码的编译过程说起了。

首先我们写的java代码会被javac静态编译器进行编译,编译成class字节码,然后会经过JIT动态编译器编译成操作系统可以执行的机器码,在编译的过程中,有一个编译优化的概念,为了提高执行效率,可能会发生指令重排,例子就是之前文章中我们说到的double check单例模式,这里就不再说明了。

除了编译会发生指令重排,CPU本身也可能改变指令的执行顺序,另外高速缓存、写缓冲器和无效队列在硬件层面也可能会改变指令的顺序。

接着我们来探索一下CPU是如何出现指令重排的?这就涉及到CPU的指令乱序和猜测执行机制了。

首先我们来看一下指令乱序机制。

CPU获取到的指令是不一定能直接执行的,比如指令要执行网络通信、磁盘IO、获取锁等,为了提升效率,CPU使用的就是指令乱序机制。

把编译好的指令一条一条的读取到处理器中,但哪条指令先就绪可以执行了,就会先执行,而不会去按照顺序执行。

然后将指令执行后的结果放入指令重排序处理器中,重排序处理器再把这些结果按照最开始的指令顺序同步到主内存或写缓冲器中。

这就是指令乱序机制,可能出现有序性问题。

除此之外还有一个猜测执行机制,比如if判断后,执行一堆代码,可能先去执行这堆代码,然后再进行判断,如果判断成立,就采纳执行的结果,否则不采纳执行的结果,这种机制也可能出现有序性问题。

说完了cpu,再来看看高速缓存、写缓冲器是如何导致内存重排序的

首先来了解两个概念,storeload

store指的是处理器将数据写入写缓冲器这一过程,load指的是处理器从高速缓存里读数据这一过程。这两个过程可能导致内存重排序,一共有四种可能:

LoadLoad重排序:一个处理器先执行L1,后执行L2,另一个处理器可能看到的是先执行L2,后执行L1;

StoreStore重排序:一个处理器先执行W1,后执行W2,另一个处理器可能看到的是先执行W2,后执行W1;

LoadStore重排序:一个处理器先执行L1,后执行W2,另一个处理器可能看到的是先执行W2,后执行L1;

StoreLoad重排序:一个处理器先执行W1,后执行L2,另一个处理器可能看到的是先执行L2,后执行W1;

为了便于理解,以StoreStore重排序为例,假如高速缓存按照W1W2的顺序接收到两个操作,为了提高性能,先执行了W2,后执行了W1,这就发生了内存重排序,其他处理器看到的顺序就是重新排序后的顺序。

总结

今天我们从硬件级别重新认识了一下可见性和有序性问题。

对于可见性,我们介绍了CPU的缓存机制和MESI协议。

对于有序性,我们介绍了编译优化、CPU的指令乱序和猜测执行、内存重排序机制导致的指令重排问题。

这就是全部内容了,希望小伙伴们能够通过对底层原理的理解,更容易的理解并发编程。

(0)

相关推荐

  • 到底什么是内存可见性?

    我们都知道,volatile保证了内存可见性和禁止指令重排,但是对于内存可见性这一条,我一直没有完全弄明白,今天咱们一起看一下,这个可见性,到底是如何可见,数据到底是如何可见的. 首先我们要达成一个共 ...

  • 看懂这篇,才能说了解并发底层技术

    零.开局 前两天我搞了两个每日一个知识点,对多线程并发的部分知识做了下概括性的总结.但通过小伙伴的反馈是,那玩意写的比较抽象,看的云里雾里晕晕乎乎的. 所以又针对多线程底层这一块再重新做下系统性的讲解 ...

  • 分布式并发编程,线程安全性,原理分析

    初步认识 Volatile 一段代码引发的思考 下面这段代码,演示了一个使用 volatile 以及没使用volatile这个关键字,对于变量更新的影响 public class VolatileDe ...

  • CPU缓存L1/L2/L3工作原理

    一.前言 在过去的几年中,计算机处理器取得了相当大的进步,晶体管的尺寸每年都在变小,而且这种进步达到了摩尔定律迅速变得多余的地步. 当涉及到处理器时,不仅晶体管和频率很重要,高速缓存也很重要. 在讨论 ...

  • 韩国恐怖片《昆岩池》将翻拍成好莱坞版,你还敢再看一遍吗?

    据消息称,知名韩国韩国恐怖片<昆岩池>将翻拍成好莱坞版,目前洛杉矶的影视经纪公司Black Box Management与韩国首尔的BH Entertainment已经签下合作协议,将这部 ...

  • 百合花上盆栽种的小技巧,超级详细,收藏再看!

    百合花是一种很漂亮的观赏花卉,其花姿态高雅,叶片清翠娟秀,茎杆亭亭玉立,高档雅致,放在卧室.客厅都合适,是名贵的切花新秀.现在很多人家的私家花园都会种一些百合花,虽然花开一季,但是能提高花园的档次,满 ...

  • 5本恨不得失忆再看一遍的小说,剧情实力精彩,错过非常可惜

    5本恨不得失忆再看一遍的小说,剧情实力精彩,错过非常可惜 第一本:<神墓> 作者:辰东 本书字数:299.5万字 已完本 书评:一本经典玄幻小说,辰东大神的代表作.天地为棋局.众生为棋子. ...

  • 100幅历代名家兰花图,看了还想再看

    中国人对于花的理解与依恋 往往是从生命的大彻大悟中得来 花之情本是人之情 晋陶渊明独爱花中隐逸的菊 自李唐以来,国人多爱富贵牡丹 而宋周濂溪则独爱花中君子的莲 梁山伯与祝英台的凄美爱情 最终也化为了恋 ...

  • 11部真实事件改编的恐怖片,了解背后的故事再看影片,恐怖效果翻倍!

    每日品经典,感受别样人生 德州电锯杀人狂 The Texas Chain Saw Massacre 导演: 托比·霍珀 编剧: 托比·霍珀 主演: 玛丽莲·伯恩斯 / 阿伦·丹齐格 豆瓣评分:7.2 ...

  • 超实用的风水理论知识,值得收藏一看再看!

    杨公风水理论是一个体系,内容由形理法课四大部分:形者形法也.理者理法也.法者方法也.课者择选曰课也. 1.论形法,一般来讲人们多讲峦头,而我称为形法,因形法里包含着峦头,峦头就是寻龙点穴之辩龙.辩穴. ...

  • 知道了这些规则,再看电路图就不感觉乱了

    在我们进行电子DIY制作时,看图是难免的,但对于很多新手来说,刚开始似乎总有种很乱的感觉,走过来后我们才知道,当时只是没有了解这些规则,今天小编以电子电路图为主要示例进行总结一下. 电路图走向 是指电 ...

  • 这才是《知音》的原唱,曾风靡一时的电影,今日再看回忆满满!

    这才是《知音》的原唱,曾风靡一时的电影,今日再看回忆满满!

  • 非常道269:再看《嗝嗝老师》

    269.再看<嗝嗝老师> 上个星期和这个星期,在我所教的两个班的五月电影课程上播放的是普通话版<嗝嗝老师>. 在我所教的上一届班中,我也推荐过这部电影,希望通过这部电影,让我班 ...