一、概述
现代计算机的发展可以分为两个阶段,一个是串行计算阶段,一个是并行计算阶段
串行计算机只有一个处理单元(processing unit), 按照顺序工作方式逐一执行程序中的指令,也就是系统的各个部件顺序处理数据
并行计算机是由一组处理单元组(Processing units)构成的,这组处理单元之间通过相互通信和协作,以更快的速度共同完成一项大规模的计算任务
二、弗林分类(Flynn's taxonomy)
弗林分类是基于指令流和数据流的数量对并行计算机进行分类的方法,是一种计算机架构的分类方法, 随着多中央处理器CPUs的发展,已经成为用作现代处理器和功能设计的工具
- 并发的指令流:基于多控制单元(control unit),每个控制单元控制指令顺序执行,一般来说,每个CPU内部只有一个控制单元,多个控制单元就是多个CPU
- 并发的数据流属于多功能单元,如ALU,一条指令可以顺序执行也可以由多个功能单元执行
1. SISD
这个类别是Single Instruction Single Data的缩写,这种类别的计算机其实就是顺序执行的串行计算机,单个control unit从单个processing unit中产生单个控制信号,指示单个功能单元在单个数据流上执行功能
2. SIMD
Single Instruction Multiple Data的缩写,单个指令同时应用于不同的数据流,指令可以按照顺序进行也可由多个功能单元并行进行,是一种典型的并行计算机
在一台SIMD计算机中,有一个control unit和很多个processing unit
各个processing unit执行的是同一个程序,通常要求实际问题中包含大量对不同数据进行的相同运算
3. MISD
Multiple Instruction Single Data的缩写,也就是多个指令要对同一个数据流进行操作,这种体系结构是很不常见的,通常用来提高容错率,可以理解为如果不同的指令对同一个数据进行操作之后得到相同的结果,那么这个结果很有可能是正确的,即便结果不相同,我们也可以知道(就像是考完试对答案一样……
4. MIMD
Multiple Instruction Multiple Data的缩写,也就是多个处理器同时对不同的数据执行不同的指令,MIMD体系结构通常使用同一个共享内存空间或者是分布式的内存空间
各个processing unit通过互联的网络进行通信,可以执行不同的程序,并且都有一个控制部件
三、对称多处理(Symmetrical Multi-Processing)
对称多处理简称SMP,是指在一个计算机上汇集了一组处理器(多CPU),各个CPU之间共享内存和一台计算机的其他资源以及总线结构,是应用很广泛的并行技术
SMP系统中有多个处理器,每一个都有自己的control unit, logic unit和寄存器,每个处理器也就是CPU都可以通过系统总线(time-shared bus)来访问一个共享的主存和I/O设备
同时,每个处理器通常都有一个专用的cache,这个cache里面含有主存的一部分数据(copy),如果某个CPU修改了其中哪怕一个数据,那么其他的CPU对应的这个数据就会无效化,这就带来了cache的一致性的问题
四、缓存一致性
根据上面的描述我们可以知道,每个CPU的cache是不共享的,但是它们却共享一个主存,在下面的图中就是Physical Memory,所以我们要考虑缓存一致性的问题
每个CPU的cache都会被进一步堪称一个个缓存行,为了方便理解,可以看成一份份数据
在下面我们都默认cache写的策略是写回(write-back)
缓存行的四种状态
1⃣️M(Modified): 表示该缓存行的数据被修改,和主存中的数据不一样,同时该缓存行只被存储在该CPU中,也就是这个CPU(local cache)独占数据
2⃣️E(Exclusive):表示该缓存行的数据和主存中的数据一致,同时local cache独享数据
3⃣️S(Shared): 表示该缓存行的数据和主存的数据一致,但是local cache和其他CPU的cache共享这份数据
4⃣️I(Invalid):表示该缓存行的数据无效
数据是否和主存一致 | 数据是否和其他cache共享 | |
M(Modified) | ❌ | ❌ |
E(Exclusive) | ✔️ | ❌ |
S(Shared) | ✔️ | ✔️ |
I(Invalid) | NULL | NULL |
状态转化
当前状态 | 发生事件 | 解释 | 下一个状态 |
M | Local Read | Local CPU读取自己修改过的数据,状态不变 | M |
M | Local Write | Local CPU再次修改自己修改过的数据,状态不变 | M |
M | Remote Read | 由于其他CPU要读取数据,所以Local CPU需要先将自己修改过的最新的数据写回主存,然后其他CPU读取,这个时候Local CPU和其他CPU的缓存行状态都变为S | S |
M | Remote Write | 由于其他CPU要修改数据,所以Local CPU需要先将自己修改过的最新的数据写回主存,然后其他CPU读取数据,然后修改,这个时候Local CPU状态变为I,修改数据的CPU状态变为M | I |
E | Local Read | Local CPU读取自己存储的数据,状态不变 | E |
E | Local Write | Local CPU修改自己存储的数据,数据和主存不一致,同时独享数据,状态变为M | M |
E | Remote Read | 其他CPU读取同样的数据,Local CPU的数据仍然和主存保持一致,但是已经不再独享数据,其他CPU状态变为S | S |
E | Remote Write | 其他CPU读取并修改这个数据,Local CPU的数据为旧的数据,无效,修改数据的CPU状态变为M | I |
S | Local Read | Local CPU读取自己存储的共享数据,数据和主存一致,状态不变 | S |
S | Local Write | Local CPU修改自己存储的共享数据,数据和主存不一致且自己独享最新的数据,状态变为M | M |
S | Remote Read | 其他CPU从主存中读取同样的数据,没有影响 | S |
S | Remote Write | 其他CPU读取并修改这份数据,Local CPU的数据变成旧的版本,不再有效,修改数据的CPU状态变为M | I |
I | Local Read | 1⃣️如果从主存中读取的这份数据没有被其他任何一个cache存储,那么local CPU数据一致 + 独享数据,状态变为E 2⃣️如果在读取之前,这份数据被其他某一个cache存储但是没有修改,状态为E或S,那么local CPU数据一致 + 共享数据,状态变为S 3⃣️在读取之前,这份数据在某一个cache X中被修改,那么X先将数据写回主存,然后Local CPU读取这份数据, Local和X的状态都变S | E/ S |
I | Local Write | 无论其他的cache是什么状态,local CPU修改数据之后,数据不一致 + 独享最新的数据,状态变为M | M |
I | Remote Read | 与local无关,状态不变 | I |
I | Remote Write | 与Local无关,状态不变 | I |