目录

  • 前言:
  • 1.什么是(Who):
  • 2.为何来(How):
    • 2.1缓存不一致带来的后果
    • 2.2解决方法:
  • 3.是什么(What)
    • 3.1数据在缓存中的四种状态:
    • 3.2MESI的六种消息(请求消息和响应消息)
    • 3.3MESI四种状态通过六种消息进行转换(利用3.1与3.2章节的知识点)

前言:

  • JVM不是真实存在的,只是一个抽象的概念。volatile关键字底层也是借助MESI缓存一致性协议和内存屏障得以实现有序性和可见性的。
  • MESI是计算机底层的协议,所有支持高并发的编程语言的底层都是基于MESI协议来保证并发安全的,所以MESI协议更有助于我们去理解底层原理,知其所以然!
  • 本期围绕着,什么是(Who),为何来(How),是什么(What),这三点内容来进行讲解该协议。

1.什么是(Who):

MESI(Modified Exclusive Shared Or Invalid)协议是基于Invalidate的高速缓存一致性协议,并且是支持回写高速缓存的最常用协议之一。 它也被称为伊利诺伊州协议(由于其在伊利诺伊大学厄巴纳 - 香槟分校的发展)。用于解决缓存一致的问题。


2.为何来(How):

2.1缓存不一致带来的后果


如上图,数据加载的流程如下:(从内存到寄存器)

  1. 将程序和数据从硬盘加载到内存中

  2. 将程序和数据从内存加载到缓存中(目前多三级缓存,数据加载顺序:L3->L2->L1)

  3. CPU将缓存中的数据加载到寄存器中,并进行运算

  4. CPU会将数据刷新回缓存,并在一定的时间周期之后刷新回内存

现在的CPU基本都是多核CPU,服务器更是提供了多CPU的支持,而每个核心也都有自己独立的缓存,当多个核心同时操作多个线程对同一个数据进行更新时,如果核心2在核心1还未将更新的数据刷回内存之前读取了数据,并进行操作,就会造成程序的执行结果造成随机性的影响,举个例子如下:

如果由两个cpu同事开始读取了int i =0,然后同同时执行如下语句,会出现如下情况:

......
int i = 0;
i++;
......

刚开始,i初始化为0,假设有两个线程A,B,

  1. A线程在CPU0上进行执行,从主存加载i变量的数值到缓存,然后从缓存中加载到寄存器中,在寄存器中执行i+1操作,得到i的值为1,此时得到i等于1的值还存放在CPU0的缓存中;
  2. 由于线程A计算i等于1的值还存放在缓存中,还没有刷新会内存,此时线程B执行在CPU1上,从内存中加载i的值,此时i的值还是0,然后进行i+1操作,得到i的值为1,存到CPU1的缓存中,
  3. A,B线程得到的值都是1,在一定的时间周期之后刷新回内存
    4.写回内存后,两次i++操作之后,其值还是1;
    可以看到虽然我们做了两次++i操作,但是只进行了一次加1操作,这就是缓存不一致带来的后果。

2.2解决方法:

在先前的解决方案中,大致有两种思路:
总线加锁的方式:

  • 先前大佬们提供了一种总线加锁的方式,而总线加锁是对整个内存进行加锁,在一个核心对一个数据进行修改的过程中,其他的核心也无法修改内存中的其他数据,这样对导致CPU处理性能严重下降。

总线加锁的方式导致CPU性能严重下降,此时我们提出了缓存一致性协议(MESI):

  • 缓存一致性协议提供了一种高效的内存数据管理方案,它只会对单个缓存行(缓存行是缓存中数据存储的基本单元)的数据进行加锁,不会影响到内存中其他数据的读写。
  • cache line,缓存行是为了简化与RAM之间的通信,高速缓存控制器是针对数据块,而不是字节进行操作的。从程序设计的角度讲,高速缓存其实就是一组称之为缓存行(cache line)的固定大小的数据块。

因此,我们引入了缓存一致性协(MESI)议来对内存数据的读写进行管理。


3.是什么(What)

3.1数据在缓存中的四种状态:

MESI的英文全程为:Modified Exclusive Shared Or Invalid,有四种状态,分别对应其英文单词,如下:

状态 具体描述 状态所在缓存对应的CPU是否独占数据 cache line 是否是最新数据 对数据的写入
M: 被修改(Modified) 该缓存行只被缓存在该CPU的缓存中,并且是被修改过的(dirty),即与主存中的数据不一致,该缓存行中的数据需要在未来的某个时间点(允许其它CPU读取主存中相应数据之前)写回(write back)主存。当被写回主存之后,该缓存行的状态会变成独享(exclusive)状态。 可以
E: 独享的(Exclusive) 该数据只被缓存在该CPU的缓存行中,它是未被修改过的(clean),与主存中数据一致。该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)。同样地,当CPU修改该缓存行中内容时,该状态可以变成Modified状态。 可以
S: 共享的(Shared) 该状态意味着该数据可能被多个CPU缓存读取,并且各个缓存中的数据与主存数据一致(clean),当有一个CPU修改自己的缓存行中的数据时,数据对应的缓存行状态变成Modified状态,其它CPU中该缓存行变成无效状态(Invalid)。 可以
I: 无效的(Invalid) 该缓存是无效的(可能有其它CPU修改了该缓存行)。 否 (无数据) 无数据 无数据,不可以

3.2MESI的六种消息(请求消息和响应消息)

cpu接收响应消息的顺序决定了其他cpu感知到的当前线程的执行顺序

  1. read:(请求消息)
    “read” 消息用来获取指定物理地址上的 cache line(如果在缓存中,从缓存中取,不在缓存中则从内存中取) 数据。
  2. read response:(响应消息)
    "read response"消息包含先前“read”消息请求的数据。此“read response”消息可能来自内存或其他CPU的缓存。
  3. invalidate:(请求消息)
    Invalidate。该消息将其他 CPU cache 中指定的数据设置为失效。该消息携带物理地址,其他 CPU cache 在收到该消息后,必须进行匹配,发现在自己的 cache line 中有该地址的数据,那么就将其从 cahe line 中移除,并响应 Invalidate Acknowledge 回应。
  4. invalidate acknowledge:(响应消息)
    该消息用做回应 Invalidate 消息。
  5. read invalidate:(请求消息)
    该消息中带有物理地址,用来说明想要读取哪一个 cache line 中的数据,同时指示其他缓存删除数据。可以看作是 read + Invalidate 消息的组合,“read invalidate”消息需要“read response”和一组“invalidate acknowledge”消息作为应答。
  6. writeback:
    “writeback”消息包含要写回内存的地址和数据(也可能是沿途“窥探”到其他cpu的缓存中)。该消息用在 modified 状态的 cache line 被置换时发出,用来将最新的数据写回 memory 或其他下一级 cache 中。

3.3MESI四种状态通过六种消息进行转换(利用3.1与3.2章节的知识点)


上图的转换详细说明:

  • a
    cache 通过 writeback 将数据回写到 memory 或者下一级 cache 中。这时候状态由 modified 变成了 exclusive 。
  • b
    cpu 直接将数据写入 cache line ,导致状态变为了 modified 。
  • c
    CPU 收到一个 read invalidate 消息,该消息中带有物理地址,用来说明想要读取哪一个 cache line 中的数据,同时指示其他缓存删除数据。此时 CPU 必须将对应 cache line 设置成 invalid 状态 , 并且响应一个 read response 消息和 invalidate acknowledge 消息。
  • d
    CPU 需要执行一个原子的 readmodify-write 操作,并且其 cache 中没有缓存数据。这时候 CPU 就会在总线上发送一个 read invalidate 消息来请求数据,并试图独占该数据。CPU 可以通过收到的 read response 消息获取到数据,并等待所有的 invalidate acknowledge 消息,然后将状态设置为 modifie 。
  • e
    CPU需要执行一个原子的readmodify-write操作,并且其local cache中有read only的缓存数据(cacheline处于shared状态),这时候,CPU就会在总线上发送一个invalidate请求其他cpu清空自己的local copy,以便完成其独自霸占对该数据的所有权的梦想。同样的,该cpu必须收集所有其他cpu发来的invalidate acknowledge之后才能更改状态为 modified。
  • f
    在本cpu独自享受独占数据的时候,其他的cpu发起read请求,希望获取数据,这时候,本cpu必须以其local cacheline的数据回应,并以read response回应之前总线上的read请求。这时候,本cpu失去了独占权,该cacheline状态从Modified状态变成shared状态(有可能也会进行写回的动作)。
  • g
    这个迁移和f类似,只不过开始cacheline的状态是exclusive,cacheline和memory的数据都是最新的,不存在写回的问题。总线上的操作也是在收到read请求之后,以read response回应。
  • h
    需要发送invalidate以通知其他cpu相应数据将要失效,并等待其他cpu的回应消息(invalidate acknowledge)。
  • i
    其他的CPU进行一个原子的read-modify-write操作,但是,数据在本cpu的cacheline中,因此,其他的那个CPU会发送read invalidate,请求对该数据以及独占权。本cpu回送read response”和“invalidate acknowledge”,一方面把数据转移到其他cpu的cache中,另外一方面,清空自己的cacheline。
  • j
    cpu想要进行write的操作但是数据不在local cache中,因此,该cpu首先发送了read invalidate启动了一次总线transaction。在收到read response回应拿到数据,并且收集所有其他cpu发来的invalidate acknowledge之后(确保其他cpu没有local copy),完成整个bus transaction。当write操作完成之后,该cacheline的状态会从Exclusive状态迁移到Modified状态。
  • k
    本CPU执行读操作,发现local cache没有数据,因此通过read发起一次bus transaction,来自其他的cpu local cache或者memory会通过read response回应,从而将该 cache line 从Invalid状态迁移到shared状态。
  • l
    当cache line处于shared状态的时候,说明在多个cpu的local cache中存在副本,因此,这些cacheline中的数据都是read only的,一旦其中一个cpu想要执行数据写入的动作,必须先通过invalidate获取该数据的独占权,而其他的CPU会以invalidate acknowledge回应,清空数据并将其cacheline从shared状态修改成invalid状态。

该篇已完结
后续将在写一篇博文介绍在Java语言中某个关键字的底层是如何用到MESI协议以及内存屏障的。
author:YuShiwen

“了解高并发底层原理”,面试官:讲一下MESI(缓存一致性协议)吧相关推荐

  1. 并发编程实战-MESI缓存一致性协议

    大家好,最近呢我对并发编程展现出了兴趣(没办法,别人都会你不会说不过去啊),然后我就要奋发图强学好并发编程,那么接下来让我们一起进入学习吧.我们在学习并发编程实战之前,应该先要了解一下我们的cpu缓存 ...

  2. 4.什么是MESI缓存一致性协议?怎么解决并发的可见性问题?

    MESI一致性协议 小陈:老王,上一章你让我看看MESI一致性协议,我大概了解了一下. 老王:哦,来说说你对MESI一致性协议的理解 小陈:MESI协议也叫做缓存一致性协议,主要是用来进行协调多核CP ...

  3. 去大厂面试,说了没高并发经验,面试官还是抓着这个问!

    我真服了,我tm现在满脑子都是"高并发",不得不说这个词真是技术圈的一个高频词. 如果不拿出这个说道说道就感觉技术非常欠缺似的.不过确实,高并发几乎是每个程序员都想拥有的经验. 原 ...

  4. 两个例子详解并发编程的可见性问题和有序性问题,通过volatile保证可见性和有序性以及volatile的底层原理——缓存一致性协议MESI和内存屏障禁止指令重排

    1. 并发编程的可见性问题 2. 并发编程的有序性问题 3. 使用volatile关键字解决可见性问题 4. 可见性问题的本质--缓存不一致 因为cpu执行速度很快,但是内存执行速度相对于CPU很慢, ...

  5. 解秘 Node.js 单线程实现高并发请求原理,以及串联同步执行并发请求的方案

    最近在做一个支持多进程请求的 Node 服务,要支持多并发请求,而且请求要按先后顺序串联同步执行返回结果. 对,这需求就是这么奇琶,业务场景也是那么奇琶. 需求是完成了,为了对 Node.js 高并发 ...

  6. 并发底层原理:线程、资源共享、volatile 关键字

    并发底层原理:线程.资源共享.volatile 关键字 1.线程 1.1 定义任务 1.2 Thread 类 1.3 使用 Executor 1.4 从任务中产生返回值 1.6 优先级 1.7 后台线 ...

  7. 关于Spring底层原理面试的那些问题,你是不是真的懂Spring?

    转载自  关于Spring底层原理面试的那些问题,你是不是真的懂Spring? 1.什么是 Spring 框架?Spring 框架有哪些主要模块? Spring 框架是一个为 Java 应用程序的开发 ...

  8. 多线程高并发 底层锁机制与优化的最佳实践——各种锁的分类 || synchronized 关键字 倒底锁的是什么东西?|| CAS与ABA问题||锁优化||轻量级锁一定比重量级锁的性能高吗

    多线程高并发 底层锁机制与优化的最佳实践 各种锁的分类 加上synchronized 关键字,共享资源就不会出错 synchronized 关键字 倒底锁的是什么东西? synchronized 锁的 ...

  9. 聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响

    Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬件差异,给上层的开发者一个一致的使用接口.Java内存模型就是这样一个中间层的模型,它为程序员屏蔽了底层 ...

最新文章

  1. 百度paddle学习笔记
  2. html漂浮广告随页面移动代码,JS漂浮广告代码,慢慢漂移的广告JS代码
  3. 新手java五子棋完整代码判断落子落在线上_Java初学者,编写小游戏五子棋的问题?...
  4. [20180102]11g的V$SORT_USAGE视图.txt
  5. c#快捷键(成为高手必备)
  6. Struts ActionForm简单理解
  7. 快速查询ABAP transport request lock status
  8. 【渝粤教育】电大中专幼儿园课程论 (1)作业 题库
  9. 如何将 byte[] 转换为 IntPtr?
  10. Go 语言初级教程之一[变量声明]
  11. [文档]CSS中文字体对照表
  12. linux zip unzip 命令
  13. 天堂2单机版服务器时间修改,如何制作最新L2J天堂2单机版源码服务端教程.doc
  14. 网页游戏开发入门教程一(webgame+design)
  15. 【Godot】项目结构设计
  16. js使用百度离线地图
  17. win11怎么关闭触控板?win11关闭触控板的三种解决方法
  18. 入门全栈Java程序员——CSS
  19. 怎样抢注到一个刚过期不久的域名?
  20. uni map 实时记录轨迹_无偏移、离线地图,追踪运动轨迹、户外旅行线路(GPS 轨迹)...

热门文章

  1. github新建分支并提交内容
  2. 【链塔DApp日报】BDI指数增长10.19%,以太坊 24h交易额增长12.27%
  3. 婚恋网站呈市场细分倾向 世纪佳缘推子品牌意欲何为
  4. qt实现读取excel文件并使用Qchart画图显示
  5. php怎么通过url传参,php使用url传参和简单结构设计
  6. 查看Mac本机的Python3的安装路径
  7. about stock
  8. 数据库性能监控工具 Spotlight on MySQL
  9. 2022年最新青海机动车签字授权人模拟试题及答案
  10. 客户案例 | 宝藏平台,企业再也不用担心运营管理那些事儿