MESI 协议:多核处理器的一致性解决方案

news2024/11/29 0:45:03

文章目录

  • 概述
  • MESI 协议的基本原理
    • 概念
    • 协议状态
  • 工作机制
    • 缓存行状态转移
    • 状态转换图
    • 状态转换表
    • 典型的状态转换示例
    • 详细的状态转换说明
  • 写缓冲区 & 失效队列
    • 写缓冲区(Store Buffer)
    • 失效队列(Invalidation Queue)
  • Java内存模型
  • 应用场景
    • 多核处理器
    • 分布式系统
  • 结论
  • 参考资料

概述

随着整个世界的发展,CPU、内存以及各种I/O设备不断升级迭代,计算机性能有了很大的提升。原先那种简单的计算机架构也随之升级。
请添加图片描述
程序是存储在磁盘,然后读取进内存中的,内存吞吐率虽然得到很大的提升,但是相对于处理器来讲,仍然非常慢。处理器要从内存中直接读取数据都要花大概几百个时钟周期,在这几百个时钟周期内,处理器除了等待什么也不能做。
随着处理器技术的发展,现代计算机系统越来越多地采用多核处理器架构来提高性能。但是仅仅是提升CPU性能是不够的,如果内存和磁盘的处理性能没有跟上,就意味着整体的计算效率取决于最慢的设备,比如磁盘。为了平衡三者之间的速度差异,最大化利用CPU,硬件层面、操作系统层面、编译器层面也都做出了很多的优化:

  • CPU增加了高速缓存
  • 操作系统增加了进程、线程
  • 优化编译器的指令,更好的利用CPU的高速缓存

在这里插入图片描述
然而,多核处理器带来了新的挑战,尤其是在处理共享内存一致性方面。每一种优化都会带来相应的问题。
如果core0在core1还未将更新的数据写回内存之前就读取了数据,并进行了操作,就会造成数据错误。
请添加图片描述

通常,CPU的L1缓存分为指令缓存(instruction cache)和数据缓存(data cache)。

为了解决这一问题,各种缓存一致性协议应运而生,如MSI,MESI,MOSI,Synapse,Firefly及DragonProtocol等。其中,MESI 协议是一种广泛应用的缓存一致性协议,用于解决多 cpu 、并发环境下,共享内存不一致问题。

本文将深入探讨 MESI 协议的基本原理、工作机制以及在多核处理器架构中的应用。

MESI 协议的基本原理

概念

MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议。
CPU操作缓存的单位是缓存行(cache line)。MESI协议就是对缓存行的状态进行标记处理,通过这些状态的切换来管理缓存数据的。
CPU中每个缓存行(caceh line)使用4种状态进行标记(使用额外的两位(bit)表示):
其中MESI分别代表缓存行数据所处的四种状态,通过这四种状态的切换来管理缓存数据,四种状态分别为Modefiy、Exclusive、Shared和Invalid,具体含义如下所示:

协议状态

MESI 协议是一种基于状态转移的缓存一致性协议,它通过维护缓存行的状态来确保多个处理器之间的一致性。MESI 协议定义了四种状态:

状态名称描述
M修改(Modefiy)该缓存行有效, 数据被修改了,但未同步回内存。即数据只存在于本缓存行中,和内存中的数据不一样
E独占(Exclusive)该缓存行有效,数据未被修改,和内存中的数据一致,并且数据只存在本缓存行中
S共享(Shared)该缓存行有效,数据未被修改,和内存中的数据一致,并且数据同时存在于其他缓存中
I无效(Invalid)该缓存行数据无效,数据已过时。
  • 在E和S状态下,缓存行的数据是有效的,任何读取操作可以直接使用;
  • 在M和I状态下,缓存行的数据是dirty(和内存的数据可能不一致)。在读取或写入数据时,需要先将其它核心已修改的数据写回内存,再从内存读取;
  • 在S和I状态,没有获得缓存行数据的独占权(锁)。想要修改数据时不能直接修改,而是要先向所有核心广播 RFO(Request For Ownership)请求 ,将其它核心的缓存行置为I,等到获得回应 ACK 后才算获得缓存行数据的独占权。
  • 在M和E状态下,核心已经获得了缓存行数据的独占权(锁)。在修改数据时不需要向总线发送广播,能够减轻总线的通信压力。

CPU感知其他CPU的行为(比如读、写某个缓存行)就是是通过嗅探(Snoop)其他CPU发出的请求消息完成的,有时CPU也需要针对总线中的某些请求消息进行响应。这被称为“总线嗅探机制”。

事实上,完整的 MESI 协议更复杂,但我们没必要记得这么细。我们只需要记住最关键的 2 点:

    1. 阻止同时有多个核心修改的共享数据:当一个 CPU 核心要求修改数据时,会先广播 RFO 请求获得 Cache 块的所有权,并将其它 CPU 核心中对应的 Cache 块置为已失效状态;
    1. 延迟回写:只有在需要的时候才将数据写回内存,当一个 CPU 核心要求访问已失效状态的 Cache 块时,会先要求其它核心先将数据写回内存,再从内存读取。

MESI 协议在 MSI 的基础上增加了 E(独占)状态,以减少只有一份缓存的写操作造成的总线通信。

MESI 协议有一个非常 nice 的在线体验网站,可以对照本文内容,在网站上操作指令区,并观察内存和缓存的数据和状态变化。
https://www.scss.tcd.ie/Jeremy.Jones/VivioJS/caches/MESI.htm

工作机制

缓存行状态转移

MESI 协议的核心在于缓存行状态的转移。当处理器需要读取或写入内存中的数据时,会触发状态转移,以确保数据的一致性。

  • 当一个处理器请求使用exclusive模式加载load一个缓存行时,其他的处理器会将所有它们自己关于该缓存行的副本都置为invalid。任何一个已修改过自己本地的该对应缓存行的处理器都需要首先将其写回到内存中,之后第一个处理器的load请求才可以被满足。
  • 当一个处理器请求使用shared模式加载load一个缓存行时,任何一个以exclusive模式加载该line的处理器都必须将其状态置为shared,并且任何一个已经修改过自己本地对应缓存行的处理器都必须将该line写回主内存,之后第一个处理器的load请求才可以被满足。
  • 如果缓存满了,则可能需要驱逐一个缓存行。如果该line是shared或exclusive状态,那么它可以直接简单的被丢弃。但是如果该line被修改过,那么它必须被首先写回内存之后再丢弃。

状态转换图

在这里插入图片描述

状态转换表

上述状态转换图等同于下表:
在这里插入图片描述

典型的状态转换示例

下面是一些典型的状态转移示例:

  • 读操作:
    • 如果处理器试图读取的数据处于 S 状态,则直接从缓存读取。
    • 如果数据处于 M 或 E 状态,则也可以直接从缓存读取。
  • 写操作:
    • 如果处理器试图写入的数据处于 E 或 M 状态,则直接写入缓存,并将状态更新为 M。
    • 如果数据处于 S 状态,则必须先向其他缓存发送失效消息(Invalidate Message),使其他缓存中的数据失效,然后才能写入本地缓存,并将状态更新为 M。

详细的状态转换说明

在这里插入图片描述

写缓冲区 & 失效队列

MESI 协议保证了 Cache 的一致性,但完全地遵循协议会影响性能。因此,现代的 CPU 会在增加写缓冲区和失效队列将 MESI 协议的请求异步化,以提高并行度:

写缓冲区(Store Buffer)

由于在写入操作之前,CPU 核心 1 需要先广播 RFO 请求获得独占权,在其它核心回应 ACK 之前,当前核心只能空等待,这对 CPU 资源是一种浪费。因此,现代 CPU 会采用 “写缓冲区” 机制:写入指令放到写缓冲区后并发送 RFO 请求后,CPU 就可以去执行其它任务,等收到 ACK 后再将写入操作写到 Cache 上。

失效队列(Invalidation Queue)

由于其他核心在收到 RFO 请求时,需要及时回应 ACK。但如果核心很忙不能及时回复,就会造成发送 RFO 请求的核心在等待 ACK。因此,现代 CPU 会采用 “失效队列” 机制:先把其它核心发过来的 RFO 请求放到失效队列,然后直接返回 ACK,等当前核心处理完任务后再去处理失效队列中的失效请求。
在这里插入图片描述
事实上,写缓冲区和失效队列破坏了 Cache 的一致性。 举个例子:初始状态变量 a 和变量 b 都是 0,现在 Core1 和 Core2 分别执行这两段指令,最终 x 和 y 的结果是什么?

# Core1 指令
a = 1; // A1
x = b; // A2

# Core2 指令
b = 2; // B1
y = a; // B2

我们知道在未同步的情况下,这段程序可能会有多种执行顺序。不管怎么执行,只要 2 号指令是在 1 号指令后执行的,至少 x 或 y 至少一个有值。但是在写缓冲区和失效队列的影响下,程序还有以意料之外的方式执行:

执行顺序(先不考虑 CPU 超前流水线控制)结果
A1 → A2 → B1 → B2x = 0, y = 1
A1 → B1 → A1 → B2x = 2, y = 1
B1 → B2 → A1 → A2x = 1, y = 0
B1 → A1 → B2 → A2x = 2, y = 1
A2 → B1 → B2 → A1(A1 与 A2 重排)x = 0, y = 0
Core2 也会出现相同的情况,不再赘述x = 0, y = 0

在这里插入图片描述
可以看到:从内存的视角看,直到 Core1 执行 A3 来刷新写缓冲区,写操作 A1 才算真正执行了。虽然 Core 的执行顺序是 A1 → A2 → B1 → B2,但内存看到的顺序却是 A2 → B1 → B2 → A1,变量 a 写入没有同步给对变量 a 的读取,Cache 的一致性被破坏了。

Java内存模型

Java内存模型( Java Memory Model),简称JMM。
它本身只是一个抽象的概念,并不真实存在。它描述的是和多线程相关的一组规范。通过这组规范,定义了程序中对各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。需要每个JVM 的实现都要遵守这样的规范,有了JMM规范的保障,并发程序运行在不同的虚拟机上时,得到的程序结果才是安全可靠可信赖的。

JMM定义了主内存和线程之间的抽象关系:
在这里插入图片描述

应用场景

多核处理器

在多核处理器系统中,MESI 协议是维护共享内存一致性的一种常用方案。通过有效地管理缓存一致性,MESI 协议使得多核处理器能够在执行并发任务时保持数据的一致性。

分布式系统

尽管 MESI 协议最初设计用于单个芯片上的多核处理器,但它的一些原则也可以应用于分布式系统中的缓存一致性管理。

结论

MESI 协议是一种高效的缓存一致性协议,它通过维护缓存行的状态来确保多核处理器系统中的共享内存一致性。通过状态转移机制,MESI 协议能够有效地处理多处理器环境中的数据一致性问题,从而提高了系统的整体性能和可靠性。

最后的补充:

    1. 在 CPU Cache 的三级缓存中,会存在 2 个缓存一致性问题:
    • 纵向 - Cache 与内存的一致性问题: 在修改 Cache 数据后,如何同步回内存?
    • 横向 - 多核心 Cache 的一致性问题: 在一个核心修改 Cache 数据后,如何同步给其他核心 Cache?
    1. Cache 与内存的一致性问题有 2 个策略:
    • 写直达策略: 始终保持 Cache 数据和内存数据一致,在每次写入操作中都会写入内存;
    • 写回策略: 只有在脏 Cache 块被替换出去的时候写回内存,减少写回内存的次数;
    1. 多核心 Cache 一致性问题需要满足 2 点特性:
    • 写传播(总线嗅探): 每个 CPU 核心的写入操作,需要传播到其他 CPU 核心;
    • 事务串行化(总线仲裁): 各个 CPU 核心所有写入操作的顺序,在所有 CPU 核心看起来是一致。

参考资料

  • MESI 协议简介
  • MESI协议
  • MESI–CPU缓存一致性协议

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2060105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue实现卡片遮罩层交互式功能

前言 在前端开发中&#xff0c;卡片遮罩层是一种常见的交互设计元素&#xff0c;用于强调某个区域或内容&#xff0c;并提供用户操作的入口。本文将带大家在 vue 中结合实际案例实现此功能。 实现效果 完整代码 html <template><!-- 主容器 --><div class&quo…

[C++] map、set 的 封装 (二):map、set和红黑树的双向奔赴

标题&#xff1a;[C] map、set 的 封装 &#xff08;二&#xff09; 水墨不写bug 前言 在正式深入进map、set封装之前&#xff0c;我有一些话想说&#xff0c;map和set的封装在初次理解时可能会比较困难&#xff0c;仅仅是模板&#xff0c;仿函数引起的回调就会把你拌入无底深…

【从Qwen2,Apple Intelligence Foundation,Gemma 2,Llama 3.1看大模型的性能提升之路】

从早期的 GPT 模型到如今复杂的开放式 LLM&#xff0c;大型语言模型 (LLM) 的发展已经取得了长足的进步。最初&#xff0c;LLM 训练过程仅侧重于预训练&#xff0c;但后来扩展到包括预训练和后训练。后训练通常包括监督指令微调和校准&#xff0c;这是由 ChatGPT 推广的。 自 …

redis AOF机制

在redis运行期间&#xff0c;不断将redis执行的写命令写到文件中&#xff0c;redis重启之后&#xff0c;只要将这些命令重复执行一遍就可以恢复数据。因为AOF只是将少量的写命令写入AOF文件中&#xff0c;因此其执行效率高于RDB&#xff0c;开启AOF即使Redis发生故障&#xff0…

Redis缓存场景

Redis缓存场景 文章目录 Redis缓存场景Redis做缓存旁路缓存缓存异常缓存穿透缓存击穿缓存雪崩 缓存一致性先写缓存再写数据库先写数据库再写缓存先删除缓存再写数据库先写数据库再删缓存缓存双删Binlog异步更新总结 Redis做缓存 部分图解来自于&#xff1a;https://www.miansh…

微课录制不再难:精选三款录屏软件助你一臂之力

在这个信息爆炸的时代&#xff0c;微课以其短小精悍、易于消化的特点&#xff0c;成为知识传播的新宠。无论是教师备课、企业培训&#xff0c;还是个人知识分享&#xff0c;微课都能以其独特的方式&#xff0c;让学习变得更加高效和便捷。在数字化教学的浪潮中&#xff0c;PPT课…

SAP SUBSCREEN使用

step1&#xff1a;在SELECTION-SCREEN中定义SUBSCREEN SELECTION-SCREEN BEGIN OF SCREEN 0101 AS SUBSCREEN. SELECT-OPTIONS S_XMGS FOR ZTPO0074-XMGS . SELECTION-SCREEN END OF SCREEN 0101.STEP2: 引用SUBSCREEN 关键字 CALL SUBSCREEN SUBSCR_0100 INCLUDING SY-RE…

Java基础核心知识学习笔记

方法重载 请记住下面重载的条件 方法名称必须相同。参数列表必须不同&#xff08;个数不同、或类型不同、参数类型排列顺序不同等&#xff09;。方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为方法的重载。重载是发生在编译时的&#xff0c;因为编译器可以根…

结合ChatGPT与Discord,提高团队合作效率

本文将教你如何集成Discord Bot&#xff0c;助力团队在工作中实现更高效的沟通与协作。通过充分发挥ChatGPT的潜力&#xff0c;进一步提升工作效率和团队协作能力。无需编写任何代码即可完成本文所述的操作&#xff0c;进行个性化定制只需对参数进行微调即可。 方案介绍 如果在…

联想闪电鲨移动硬盘文件没删除却消失了怎么办

在日常的数据存储与管理中&#xff0c;移动硬盘作为便携且容量可观的存储设备&#xff0c;深受用户青睐。然而&#xff0c;当您发现联想闪电鲨移动硬盘中的文件突然消失&#xff0c;而您确信并未进行删除操作时&#xff0c;这无疑会令人感到困惑与焦虑。本文旨在为您揭开这一谜…

MySQL各个版本root账号没有最高权限的解决方法

一、详细报错 ERROR 1045 (28000): Access denied for user ‘root’‘localhost’ (using password: YES) 报错原因&#xff08;分析过程&#xff09;&#xff1a; rootlocalhost用户密码修改导致 解决方法&#xff1a; 跳过权限验证启动数据库&#xff0c;并修改密码。如下…

[028-3].第05节:RabbitMQ中的交换机

1.什么是Exchanges(交换机&#xff09;: 1.RabbitMQ 消息传递模型的核心思想是: 生产者生产的消息从不会直接发送到队列。实际上&#xff0c;通常生产者甚至都不知道这些消息传递传递到了哪些队列中2.生产者只能将消息发送到交换机(exchange)&#xff0c;交换机工作的内容非常…

C++ TinyWebServer项目总结(7. Linux服务器程序规范)

进程 PID 进程的PID&#xff08;Process ID&#xff09;是操作系统中用于唯一标识一个进程的整数值。每个进程在创建时&#xff0c;操作系统都会分配一个唯一的PID&#xff0c;用来区分不同的进程。 PID的特点 唯一性&#xff1a; 在操作系统运行的某一时刻&#xff0c;每个…

江苏省第二中医院案例│“互联网+医疗”下的灾备建设

江苏省第二中医院&#xff0c;成立于1988年12月&#xff0c;是一所融医疗、教学、科研、预防保健为一体的公立省级综合性三级甲等中医院。目前&#xff0c;正对照“大学附属医院”“省级三甲医院”建设标准&#xff0c;全面推进医院建设高质量跨越式发展。 用户需求&#xff1a…

冒 泡 排 序

今天咱们单独拎出一小节来聊一聊冒泡排序昂 冒泡排序的核心思想就是&#xff1a;两两相邻的元素进行比较&#xff08;理解思路诸君可看下图&#xff09; 接下来我们上代码演示&#xff1a; 以上就是我们初步完成的冒泡排序&#xff0c;大家不难发现&#xff0c;不管数组中的元…

智能停车计费系统设计与实现_urqs9

TOC springboot552智能停车计费系统设计与实现_urqs9--论文 绪 论 1.1 研究背景 在新世纪的今天&#xff0c;计算机已经发展到一定的规模&#xff0c;带动了国内经济和科学技术的快速发展&#xff0c;科学技术的发展大大提高了生产效率&#xff0c;使人们的物质生活需求得到…

为啥每个语音的printf(“%d%d%d%d“,i,j,i++,j++)不一样

题目来源一位考研同学的题目。 第一眼&#xff1a;小子&#xff0c;这都不会&#x1f600; 第二眼&#xff1a;wok&#xff0c;咋没有选项&#x1f622; 作为一个大一学C语音&#xff0c;大二学Java的同学来说&#xff0c;我一看就觉得肯定是11 6 11 6 。 结果很遗憾&#xff0…

微服务开发相关问题

微服务开发相关问题 服务注册nacos 2.X注册问题[Nacos Config] config[dataIddatasource.yml, groupDEFAULT_GROUP] is empty 参考 持续更新… 服务注册 nacos 2.X注册问题 [Nacos Config] config[dataIddatasource.yml, groupDEFAULT_GROUP] is empty 因为&#xff1a;# 由于…

C++第十二弹 -- STL之list模拟实现

文章索引 前言模拟实现list1. ListNode节点类2. list的迭代器封装3. 反向迭代器4. list类的模拟实现测试代码 list的反向迭代器总结 前言 通过模拟实现可以让我们更加深刻的理解C底层STL的实现逻辑, 本篇就对list的底层进行模拟实现. 博客主页: 酷酷学!!! 点击关注 共同进步!…

影响五金精密零件加工价格的因素

在制造业中&#xff0c;五金精密零件的加工价格受到多种因素的影响。了解这些因素&#xff0c;对于企业合理控制成本、选择合适的加工供应商至关重要。 首先&#xff0c;零件的设计复杂度是一个重要因素。复杂的设计通常需要更先进的加工技术和更多的加工工序。例如&#xff0c…