线程级并行是多处理器支持多个线程同时并行执行,多处理器体系结构大致分成两种:
并行处理面临2个重要的挑战:
解决这两个问题的策略为:
假设处理器A和B先后读取X(各自的缓存中存有X的副本),A修改了X并写回到主存,但此时B的缓存中X仍然是未修改的X,发生了缓存不一致现象
保证缓存一致性有两种策略:
实现缓存一致性有两种方法:
由于写更新需要占用相当多的带宽(有时还可能不必要),一半采取写失效的方法
简单的监听一致性协议为专用缓存中的缓存块分配一个有效位(标志有效或无效)以及一个状态位(标志共享还是独占),那么一个缓存块有三种状态(无效块状态位无意义):
监听协议中有几个关键动作:
把上述通知按请求的形式给出并按其发送源分类有一下完整的动作:
源 | 请求 | 寻址缓存块状态 | 缓存操作类型 | 动作 |
---|---|---|---|---|
处理器 | 读命中 | 共享或独占 | 正常命中 | 直接读取本地缓存数据 |
处理器 | 读缺失 | 失效 | 正常缺失 | 向总线发送读缺失请求,请求数据装入缓存后读取,并标记为共享 |
处理器 | 读缺失 | 共享 | 替换 | 向总线发送读缺失请求,请求数据装入缓存替换原共享块后读取,并标记为共享 |
处理器 | 读缺失 | 独占 | 替换 | 写回独占块并标记为共享,向总线发送读缺失请求,请求数据装入缓存替换原独占块(现标记是共享)后读取,并标记为共享 |
处理器 | 写命中 | 共享 | 一致性 | 写入并标记独占,然后把失效请求放在总线上 |
处理器 | 写命中 | 独占 | 正常命中 | 直接写入本地缓存 |
处理器 | 写缺失 | 失效 | 正常缺失 | 向总线发送写缺失请求,请求数据装入缓存后写入,并标记为独占 |
处理器 | 写缺失 | 共享 | 替换 | 向总线发送写缺失请求,请求数据装入缓存替换原共享块后写入,并标记为独占 |
处理器 | 写缺失 | 独占 | 替换 | 先写回独占块并标记为失效,向总线发送写缺失请求,请求数据装入缓存替换该失效块后写入,并标记为独占 |
总线 | 读缺失 | 共享 | 无操作 | 允许共享块并不做动作 |
总线 | 读缺失 | 独占 | 一致性 | 写回独占块并标记为共享 |
总线 | 写缺失 | 共享 | 一致性 | 标记该共享块失效 |
总线 | 写缺失 | 独占 | 一致性 | 写回该独占块,并标记失效 |
总线 | 失效 | 共享 | 一致性 | 标记该共享块失效 |
注意:上述独占状态即MSI协议(该简单一致性协议的另一种称呼)的Modified已修改状态(书上有时候叫它独占、有时候叫它已修改需要区分开来)
MSI有一个缺陷,先读一个block(读缺失)然后修改一个block时(写命中),将产生2个总线事务(读缺失时I->S,写命中时S->M并发送失效),即使是一个块“独占”这个读取的块时写命中也会在总线上发布失效请求,并且这种情形在多道程序负载时十分普遍
为了减少总线事务,针对这种情形提出了MESI协议,扩展了状态Exclusive State来表示仅有当前缓存中有该块副本并且该块是干净的(为了和之前独占的称呼区别开,我称它为干净独占状态),即该块和主存中的块是一致的
对干净独占状态的块写入时,不产生总线写失效请求(因为事先已经知道其他缓存中没有该块副本,失效请求无意义),则上述“先读后写”的操作只产生一次总线事务,得到优化(注意:写入已修改状态的块时也不产生失效请求)
由干净独占状态的定义我们知道只有一种情况能够产生这种状态:读失效时发现没有其他缓存有该块副本,并从主存加载该块
我的疑问:判断其他缓存中是否有该块副本不是需要在存储器块中增加标志位(复杂情况增加标志位也无法解决),那么是否这个判断过程又讲产生其他的总线事务呢?我认为是的
经余老板提点,MESI也引入Cache-to-Cache的共享,若其他缓存监听到读缺失时检测到自己有相应块的副本时,终止内存访问而主动提供该块副本
然而我又有进一步的疑问:但这样多块都有S的相应副本,都去终止内存访问发送自己缓存中的副本?这不算是额外的开销?或者这样总线不会乱套(虽然发送的是相同数据)?[PS:这就是不听课的下场,花样作死]
MOESI在MESI的基础上增加了Owned拥有状态,表示一个块由该缓存拥有并和其他缓存共享该块,并且主存中该块已经过时
MOESI针对的情形是Cache-to-Cache的共享,即缺失时不向主存中索要副本而是在其他Cache中寻求副本(思想是Cache访问快于主存访问)
那么在MOESI中,尝试共享缓存A中已修改的块时不会将该块写回,A标记其为拥有,尝试获取该块共享的缓存从A中获取缓存副本,并标记为共享(只有A中标记为拥有);那么以后都需要保持这种行为,即发生缺失时,拥有某块的缓存必须主动提供拥有块的副本;拥有块被替换时再写入主存
DSM中不采用监听一致性协议,是因为:
由此引入另一种一致性协议:目录一致性协议,目录也是分布式的位于各个节点中,和节点的存储器一一对应,即存储器中每块的状态记录在目录中;布式目录寻址和分布式存储器寻址相同,在DSM中各目录共用同一地址空间
目录一致性协议有三种状态:
因此目录中不仅要记录存储器块的缓存状态,还要用一个位向量来记录共享/修改的节点
定义三种节点类型:
弄懂几类节点间的关系就很容易理解目录一致性协议:
最后也在表中给出目录一致性协议的完整状态转换和相应动作:
[记P为发出请求节点编号、A为所请求的地址、D为所请求的数据]
消息类型 | 来源 | 目标 | 消息内容 | 消息功能 |
---|---|---|---|---|
读缺失 | 本地缓存 | 主目录 | P,A | 节点P在地址A发生读缺失,请求数据并将P加入共享节点列表 |
写缺失 | 本地缓存 | 主目录 | P,A | 节点P在地址A发生写缺失,请求数据并将P记录为独占节点,然后主目录发送失效 |
失效 | 本地缓存 | 主目录 | A | 主目录向所有缓存了A的节点(远程缓存)发送失效 |
失效 | 主目录 | 远程缓存 | A | A处共享副本失效 |
取数据 | 主目录 | 远程缓存 | A | 取回地址A的块,发送到主目录,并标记为共享 |
取数据失效 | 主目录 | 远程缓存 | A | 取回地址A的块,发送到主目录,并标记为失效 |
数据应答 | 主目录 | 本地缓存 | D | 从主节点返回数据值 |
数据写回 | 远程缓存 | 主目录 | A,D | 写回地址A的数据值 |
同步问题最主要的一些概念:
这些概念《操作系统》课程中的基本概念,这里就不再复习了
存储同一性(也叫连贯性)指的是:在多个处理器对不同存储单元并发读写操作时,每个进程看到的这些操作被完成的序的一种约定
而存储一致性是保证的是当对共享存储空间中的某一单元修改后,对所有读取者是可见的,它不涉及:
顺序同一性模型要求所有处理器读写操作串行执行所形成的全局存储器访问次序必须符合原有程序的顺序,即无论指令流如何交替执行,全局次序必须保证所有程序局部次序
顺序同一性的充分条件:
注:这一块看的不是很懂,举例将以后补充