[TOC]
现在的处理器都是多核处理器,并且每个核都带有多个缓存(指令缓存和数据缓存,见下图)。为什么需要缓存呢,这是因为CPU访问内存的速度比较慢,所以在CPU和内存之间加了个缓存以提高访问速度。既然每个核都有缓存,那么假设两个核或者多个核同时访问同一个变量时这些缓存是如何进行同步的呢(缓存细分为一个个缓存行),这就有了MESI协议。
\缓存行的四个状态:**
MESI中每个缓存行都有四个状态,分别是E(exclusive)、M(modified)、S(shared)、I(invalid)。下面我们介绍一下这四个状态分别代表什么意思。
M:代表该缓存行中的内容被修改了,并且该缓存行只被缓存在该CPU中。这个状态的缓存行中的数据和内存中的不一样,在未来的某个时刻它会被写入到内存中(当其他CPU要读取该缓存行的内容时。或者其他CPU要修改该缓存对应的内存中的内容时(个人理解CPU要修改该内存时先要读取到缓存中再进行修改),这样的话和读取缓存中的内容其实是一个道理)。
E:E代表该缓存行对应内存中的内容只被该CPU缓存,其他CPU没有缓存该缓存对应内存行中的内容。这个状态的缓存行中的内容和内存中的内容一致。该缓存可以在任何其他CPU读取该缓存对应内存中的内容时变成S状态。或者本地处理器写该缓存就会变成M状态。
S:该状态意味着数据不止存在本地CPU缓存中,还存在别的CPU的缓存中。这个状态的数据和内存中的数据是一致的。当有一个CPU修改该缓存行对应的内存的内容时会使该缓存行变成 I 状态。
I:代表该缓存行中的内容时无效的。
EMSI状态转移图:
local read和local write分别代表本地CPU读写。remote read和remote write分别代表其他CPU读写。建议首次看EMSI内容的可以自己把下面这个表格写下来(我自己就是这么做的),这样理解会深一点。
当前状态 | 事件 | 行为 | 下一个状态 |
---|---|---|---|
I(invalid) | local read | 1.如果其他处理器中没有这份数据,本缓存从内存中取该数据,状态变为E2.如果其他处理器中有这份数据,且缓存行状态为M,则先把缓存行中的内容写回到内存。本地cache再从内存读取数据,这时两个cache的状态都变为S3.如果其他缓存行中有这份数据,并且其他缓存行的状态为S或E,则本地cache从内存中取数据,并且这些缓存行的状态变为S | E或S |
local write | 1.先从内存中取数据,如果其他缓存中有这份数据,且状态为M,则先将数据更新到内存再读取(个人认为顺序是这样的,其他CPU的缓存内容更新到内存中并且被本地cache读取时,两个cache状态都变为S,然后再写时把其他CPU的状态变为I,自己的变为M)2.如果其他缓存中有这份数据,且状态为E或S,那么其他缓存行的状态变为I | M | |
remote read | remote read不影响本地cache的状态 | I | |
remote write | remote read不影响本地cache的状态 | I | |
E(exclusive) | local read | 状态不变 | E |
local write | 状态变为M | M | |
remote read | 数据和其他核共享,状态变为S | S | |
remote write | 其他CPU修改了数据,状态变为I | I | |
S(shared) | local read | 不影响状态 | S |
local write | 其他CPU的cache状态变为I,本地cache状态变为M | M | |
remote read | 不影响状态 | S | |
remote write | 本地cache状态变为I,修改内容的CPU的cache状态变为M | I | |
M(modified) | local read | 状态不变 | M |
local write | 状态不变 | M | |
remote read | 先把cache中的数据写到内存中,其他CPU的cache再读取,状态都变为S | S | |
remote write | 先把cache中的数据写到内存中,其他CPU的cache再读取并修改后,本地cache状态变为I。修改的那个cache状态变为M |
总线嗅探
当其他CPU使用这个变量时,首先会去嗅探是否有对该变量更改的信号,当发现这个变量的缓存行已经无效时,会从新从内存中读取这个变量。