MESI 缓存一致性协议

本文目录

  • 场景再现
  • 1.总线锁
  • 2.MESI 缓存一致性协议
    • 1.MESI 协议概念
    • 2.通过例子来介绍 MESI 协议
      • 1.MESI 场景
      • 2.MESI 协议下,执行步骤
      • 3.MESI协议失效问题

场景再现

场景:
  服务器有2个线程t1、t2在跑。都对 x=1 分别+1,期望最终结果:x = 3

问题分析:
  首先会将 x=1 加载到主内存中,然后 t1线程,会获取到 x=1 的内存地址,然后在寄存器、CPU缓存(L1、L2、L3)中是否存在(L1最优先,L2中如果有,则copy一份到L1,最后加载到寄存器进行计算),如果都没有则会去主内存中获取,然后一次加载,并copy到L3→L2→L1,最后写入寄存器进行计算,一级一级进行缓存。

实际结果:
  同一时刻两个线程同时运行,则会在各自线程中的 CPU 缓存中,同时有两份 x=1 的副本,然后两个线程都 +1 后,再同步写入到主内存中,此时两个线程最终结果应该为 1+1+1=3,但是预期结果会是2(t1线程写入后,t2也写入,都是1+1,写入的都是2),会导致结果和预期的不一致。

  多线程环境下,同时对一个共享变量进行操作,每个线程中都有各自的缓存模块。在这种情况下就会出现示例中出现的情况。这种情况就是并发编程中的三大问题之一:可见性,此处先行透露一下,本文不对可见性做进一步的介绍,在后续系列文章中会做介绍,请持续关注《并发编程专题》。

  在 CPU 层面,为了保证运算结果的一致性,设计了两种方式来解决这个问题:①总线锁②MESI缓存一致性协议,本文就一起来了解这两种方式。

![在这里插入图片描述](https://img-blog.csdnimg.cn/2019122017390262.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x6YjM0ODExMDE3NQ==,size_16,color_FFFFFF,t_70)

1.总线锁

  总线锁,顾名思义就是在总线上加一把锁。还不了解计算机总线的朋友,来这里了解一下:计算机原理结构

  某个CPU核心线程1去访问数据进行操作,会在总线上发送一个 LOCK 指令操作;CPU其他核心线程2请求数据操作时,便会被阻塞(总线锁相当于排它锁/悲观锁),如下图所示:
MESI 缓存一致性协议_第1张图片
   即使你的 CPU 是6核128线程,同样只能有1个线程执行,加总线锁,会严重影响机器的性能!!!。显然总线锁是不可取的,接下来我们就来聊聊 MESI 缓存一致性协议

  CPU 支持 MESI 协议的话,优先使用缓存一致性协议

2.MESI 缓存一致性协议

  缓存一致性协议,可以先BaiDu简单了解一下:MESI 缓存一致性协议。加入 MESI 缓存一致性协议后, CPU 架构如下图所示:
MESI 缓存一致性协议_第2张图片

1.MESI 协议概念

  MESI协议是一个基于失效的缓存一致性协议,是支持写回(write-back)缓存的最常用协议。也称作伊利诺伊协议 (Illinois protocol,因为是在伊利诺伊大学厄巴纳-香槟分校被发明的)。与写穿(write through)缓存相比,回写缓冲能节约大量带宽。总是有“脏”(dirty)状态表示缓存中的数据与主存中不同。MESI协议要求在缓存不命中(miss)且数据块在另一个缓存时,允许缓存到缓存的数据复制。与MSI协议相比,MESI协议减少了主存的事务数量。这极大改善了性能!!!。  (摘自:维基百科:MESI协议)

 缓存最小的单位:缓存行

 MESI 协议就是基于缓存行进行操作,缓存行有4种不同的状态:MESI

  1. Modified (M)
    缓存行是脏的(dirty),与主存的值不同。如果别的CPU内核要读主存这块数据,该缓存行必须回写到主存,状态变为共享(S).
  2. Exclusive (E)
    缓存行只在当前缓存中,但是干净的(clean)–缓存数据同于主存数据。当别的缓存读取它时,状态变为共享;当前写数据时,变为已修改状态。
  3. Shared (S)
    缓存行也存在于其它缓存中且是干净的。缓存行可以在任意时刻抛弃。
  4. Invalid (I)
    缓存行是无效的

2.通过例子来介绍 MESI 协议

  通过多线程示例,我们来分析一下 MESI 协议四个状态的切换过程,本例以两个线程来分析,如需更深入了解 MESI 协议每个状态的更多切换过程,建议去其他文章了解,本文只是简单介绍,不做深层次学习。

1.MESI 场景

  场景:线程1和线程2,都执行程序 x=1,分别对 x 加1,期待结果是:x=3

  说明: 线程1运行在 CPU 核1 线程2运行在 CPU 核2(以多核CPU为例,如下图所示)
MESI 缓存一致性协议_第3张图片

2.MESI 协议下,执行步骤

  1. 线程1从主内存获取数据,并将数据(操作的是内存地址)写入到自己核的CPU缓存(3级缓存,L3、L2、L1 依次写入),基于 MESI 缓存一致性协议,此时 x=1 属于 E(独占) 状态;
  2. 在线程1操作同时,线程2也在做相同的操作,同样对 x 加1。同样将 x=1 读取到自己的缓存中,此时同样 x=1
  3. 利用CPU 嗅探技术(类似监听机制,都在不停监听总线情况),核1(线程1)嗅探到核2(线程2)也有在使用相同的内存地址,会将线程1中 x=1 由 E(独占) 变为 S(共享),此时线程2 中 x=1 同样也是 S(共享) 状态;
  4. 每个线程,都在不停歇嗅探总线情况。线程1在获取到 x=1 后,在 CPU 中进行计算,计算完成后,会将数据回写到 CPU 缓存中(用作备份,依次L1、L2、L3),此时线程1准备写入主内存时,会向总线发送消息并锁住当前[缓存行],同时将状态由 S(共享) 变更为 M(修改) 状态;
  5. 线程2(CPU核)此时嗅探到:相同的内存地址 (x=1) 状态已经发生变更线程2 会将自己的 x=1 的状态由 S(共享) 变更为 I(无效) 状态;
  6. 线程1将最终结果:x=2,写入到主内存中
  7. 线程2在执行过程中,获取的 x=1 内存地址由于被其他线程已经修改,状态置为 I (无效)此时便会重新去主内存获取x值,获取到的就是最新的 x=2,继续经过缓存,CPU计算,将最终结果写入 主内存 中;
  8. 此时如果再来个线程3,同样对该内存地址进行操作,则重复执行步骤1。(参照上图)

3.MESI协议失效问题

在如下两种情况下,MESI 协议会失效:

  1. 如果主内存中的数据,存储长度大于一个缓存行,MESI协议便会失效;

  2. 古老的CPU,并不支持缓存一致性协议,比如:老的奔腾系列CPU;

怎么办呢?

  如果 MESI协议 失效,或者 CPU 根本不支持 MESI协议,则会退而求其次,采用 总线锁 方式解决缓存一致性问题。

  2021-11-15,MESI 缓存一致性协议已更新,接下来涉及到的 JMM 内存模型、MESI 协议在 JMM 内存模型中的8种交互操作等内容,如有需要,请持续关注《并发编程》板块!!!


博主写作不易,加个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

我不能保证所写的内容都正确,但是可以保证不复制、不粘贴。保证每一句话、每一行代码都是亲手敲过的,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

你可能感兴趣的:(并发编程,MESI,MESI,缓存一致性协议)