Skip to content

算法Algorithm

目录一致性与异步权限交接

Directory cache coherence · Directory-based coherence protocol

把共享副本撤销、脏数据返回和新权限安装拆为可乱序消息,逐步核验目录协议的等待集合、最新值交接与进展条件。

一份写请求已经发出,并不表示其他核心已经停止读取。请求者可能先得到数据,某个旧读者却还没收到失效消息。目录协议需要把“知道谁持有副本”进一步变成“已经确认这些权限撤回”。本页把每条消息分开执行,直到能指出写权真正生效的那一步。

形式陈述 ​

单块、单目录和可乱序消息 ​

沿用MSI 的 I/S/M 权限与最新值交接:I 禁止访问,S 只读,M 独占读写。旧页把一次总线事务作为原子步骤;这里没有总线广播顺序,而是一个块对应一个目录控制器 home。块只有一个整数 word,每次写替换该整数,所有数据消息携带完整块。

固定 N≥1 个缓存。消息可靠、恰好交付一次,但任意两条消息可以乱序。处理一条消息、安装权限或执行一次本地操作各是原子步骤;发送不阻塞,缓冲无界。没有逐出、失效重启、超时、取消或损坏消息,也不考察不同块之间的内存排序。这些是协议输入条件,不能由单块证明推导出来。

每个缓存保存 (权限,值,pending),至多有一个未完成的应用操作。远程请求带身份 q=(缓存编号,该缓存递增序号),序号在执行期间不回绕。S 等待升级时仍保存 S 权限;收到别人的 Inv 必须先变 I,自己的 pending 不能丢弃。pending 存在时应用不再发下一操作,但控制消息照常处理。

home 保存内存值、共享者集合或独占 owner,以及一个活动事务。后到请求放入FIFO 队列,顺序取决于请求实际抵达 home 的次序。活动事务还保存请求身份、阶段、待确认者集合与原 owner;在收到 Installed 前不开始下一事务。不能只看 home 的 owner 字段推断缓存已经有 M:发出 GrantM 后,这个字段先指向预定接收者,安装尚可能在途。

本地操作和完整消息规则 ​

没有 pending 时,S/M 读是本地命中;M 写也是本地命中。I 读发送 GetS,I/S 写发送 GetM,并登记 pending。请求本身没有授予任何新权限。

home 开始处理的请求 当前稳定持有情况 先做什么 何时可以发授权
GetS 无 M 从当前内存取值 立即发 GrantS
GetS 某缓存持 M 向它发 FwdS 收到该 owner 的 Data 后
GetM 无 M 对共享者中除请求者外的每一个发送 Inv 等待集合变空后
GetM 某缓存持 M 向它发 FwdM 收到该 owner 的 Data 后

当共享者集合为空,GetM 的等待集合也为空,可以立即发 GrantM。请求者原来是 S 时,仍会收到完整数据;我们不使用“申请时已有数据,所以只发升级许可”的优化。

消息接收规则如下,每行中的状态改变和后续发送在同一步完成:

接收消息 必须满足的条件 状态更新与发出的消息
缓存收 Inv(q) 当前为 S,可同时有自己的 pending 变 I,清掉有效值,保留 pending,向 home 发 InvAck(q)
缓存收 FwdS(q) 当前为 M 捕获最新块,降为 S,向 home 发 Data(q,块)
缓存收 FwdM(q) 当前为 M 捕获最新块,变 I,向 home 发 Data(q,块)
home 收 InvAck(q) q 是活动事务,发送者属于等待集合 删除这一发送者;集合空时发 GrantM
home 收 Data(q,块) q 正在等数据,发送者是记录的原 owner 更新内存;GetS 保留旧 owner 为共享者,GetM 清掉旧持有者;再发相应 Grant
缓存收 GrantS/GrantM(q,块) q 匹配本地 pending,权限与读写类型匹配 安装 S/M 与数据,完成这次读或写,清 pending,发 Installed(q)
home 收 Installed(q) q 匹配活动事务,发送者就是请求者 结束事务,立即从队列取下一项(若有)

发 GrantS 时,把请求者加入共享者集合;发 GrantM 时,清空共享者集合并把 owner 指向请求者。整个安装等待期仍由当前活动事务占住 home。读在安装时返回块值,写在安装 M 后原子替换块值。Installed 只是报告这一步已经发生,并不是再执行一次写。

这些规则定义的是一个保守、可完整执行的教学协议。教材中更高并发的目录协议允许多个阶段重叠,需要更多瞬态和网络条件;本页没有把那些优化省略后仍沿用它们的性能结论。

直觉

三种等待,各自排除一种风险 ​

InvAck 回答“旧读者已经失效了吗”。等待集合最初是实际应撤销的缓存身份集合,每份确认只删除对应成员。只看收到了几条任意消息不够;消息的事务身份、发送者和种类都必须匹配。

Data 回答“最后一个写者留下的值在哪里”。旧 M 收到转发请求之前仍可本地写,所以 home 不能使用请求发出时的旧内存值。旧 owner 在处理 Fwd 的那一步捕获当时最新值,并同时失去写权;从这以后没有写者能再改掉正在交接的那份数据。

Installed 回答“下一次转发能否由新持有者处理”。即便 home 已经发出 Grant,网络仍可能把它延迟。等安装确认回来后再启动后继事务,就不会向一个尚为 I 的目标转发 owner 请求。这多一次确认的成本,换来更小的瞬态状态空间。

一次升级途中,又收到撤销 ​

A、B 都持有 S(0),C 申请写10。home 先处理 C,于是向 A、B 发 Inv。A 随后也申请写20,它的 GetM 排在 C 后面。此时 A 不能因为“我已经申请升级”而拒绝 C 的撤销。

先让 Inv 到 A,再让 A 的 InvAck 回 home。A 变 I,但写20的 pending 还在;home 的等待集合只剩 B。此时 B 仍可本地读0,这完全合法,因为 C 尚未获得 M,也尚未完成写10。

上半图在等待集合只剩B时停住;下半图显示C的11暂在Data中,最后A与B共同读20

当 B 也失效并确认后,C 才收到 GrantM,安装并写10。C 可以在 Installed 尚未回到 home 时再本地写11;home 仍不能开始 A 的请求。随后 A 的 GetM 被处理,FwdM 让 C 把11交回、变 I。A 收到11后获得 M,再完成自己的写20。

A 的旧 S 副本早已失效,所以这次授权必须有完整数据。实际写把整 word 改成20,容易掩盖一次错误的旧值传输;参考器额外在执行写之前检查授权数据确实是当前块,不能只看写后的最终值。

例子与边界

从0到20的完整账本 ​

先让 A、B 各读一次0,等待各自事务完全结束,得到两个 S(0)。每次读有 GetS、GrantS、Installed 三条消息。之后按上一节让 C 的 GetM 先抵达,再让 A 的 GetM 排队。B 失效之后也发 GetS,排在 A 后面。

观察点 A B C home 内存 正在等待什么
预热完成 S(0) S(0) I 0 无
收到 A 的 InvAck I,写20待办 S(0) I,写10待办 0 B 的 InvAck
C 安装后又本地写11 I,写20待办 I,读待办 M(11) 0 C 的 Installed
C 处理 FwdM 之后 I,写20待办 I,读待办 I 0 携带11的 Data
A 安装并写20 M(20) I,读待办 I 11 A 的 Installed
B 的读结束 S(20) S(20) I 20 最后一个 Installed 回来后空闲

第四行所有缓存都 I,内存却还不是最新值。这不是丢数据:最新11已经封在不可变的 Data 消息中。异步协议的数据不变量必须把在途载体包括进来,不能逐字沿用旧原子事务末尾的“无 M 就是内存最新”。

对有 s 个其他共享者的 GetM,消息数为 1+2s+2=2s+3:一个请求、每个共享者的一次 Inv 与一次 InvAck、一次 Grant 和一次 Installed。当前 C 的事务 s=2,所以7条。向脏 owner 取数据的 GetS/GetM 都是请求、Fwd、Data、Grant、Installed,共5条。主例总计 6+7+5+5=23 条;C 的第二次写与 B 未失效前的读都是零消息命中。

三种删掉步骤后的失败 ​

未收齐确认就授权。 在等待集合为 {B} 时,假装它已经为空,给 C 发 GrantM 并让 C 写10。此刻 C=M(10)、B=S(0),权限已经矛盾;B 的下一次本地读还会返回旧0。这不是靠“最终消息都会到”能补救的,因为错误读取已经可以发生。

用旧内存替代脏数据。 A 持 M(11),home 仍为0,B 申请读。A 降为 S 后若 home 丢弃返回的11,改以0授权 B,就会得到 A=S(11)、B=S(0)。M 的数量检查会通过,数据检查却失败;必须同时核对权限和内容。

发出 Grant 就提前处理下一项。 A 的写请求使 home 发出 GrantM,但该消息尚未到 A;此时提前开始 B 的读,向预定 owner A 发 FwdS。任意乱序网络可以先交付 FwdS,此时 A 还是 I,处理表没有合法的供数动作。增加别的等待状态可以设计另一种协议,本页选择用 Installed 握手排除这条轨迹。

改变竞争次序,结果也会改变 ​

若先让 A 的 GetM 抵达 home,再让 C 的 GetM 抵达,A 的20会先完成,C 随后完成10。两者结束后让 B 读,答案是10,不是原轨迹的20。网络排序改变了允许的执行次序;协议保证每次读与实际完成的写一致,并不保证由发请求的墙钟时间决定胜者。

N=1 时,读缺失仍有三条消息,S 升 M 的撤销集合为空,也只需三条。不能把“没有其他共享者”解释成不需要取到授权。消息若可以永远不交付,等待可以无限长;安全不变量不提供毫秒级完成期限。

推论与应用

按每条消息保持权限与数据 ​

令 V 为最近一次完成的应用写的值,初始取内存初值。它是证明中的抽象量,不是协议可以向外查询的额外服务。归纳保持:至多一个 M;存在 M 时其他缓存全 I;所有有效缓存的值均为 V。若没有 M,内存为 V,或者活动事务正等待旧 owner 已经发出的 Data,且该消息携带 V。

初态各缓存 I,内存为 V。本地读不改变权限和数据;M 本地写只改变唯一有效副本并同时更新 V。Get 请求入队只增待办,不赋权。

在共享阶段,Inv 只减少读权限,InvAck 在失效以后才发出。home 只有逐一删完等待集合才发 GrantM,此时除请求者可能仍有 S 外,其他缓存均 I;请求者安装 M 并写入只会留下一个有效副本。GrantS 仅在没有 M 且内存已经最新时发出,不会制造读写并存。

在脏交接阶段,旧 M 可以在 Fwd 到达前继续写;处理 Fwd 时捕获的正是那时的 V。同一步撤回 M,因此 Data 在途时没有其他写者;后续 Data 接收与 Grant 不会把旧值越过更新值。GetS 让旧 owner 保留 S,GetM 让其变 I,两者都保持有效副本一致。

最后,Installed 只能由已经安装权限的请求者发出。home 收到它以后才启动下一项,所以下一次所列 owner 或共享者都已真实可处理控制消息。等待升级的缓存仍接受 Inv,消除了“握着旧 S 等新 M,同时拒绝别人撤销”的循环。以上覆盖本地操作和全部消息种类,故不变量按事件数保持。

进展与真实执行成本 ​

再加公平交付、公平处理和有限个应用操作,每个活动事务只等有限组 InvAck、一次 Data 或一次 Installed。这些响应都不依赖另一个应用操作完成,控制消息也不会被 pending 阻塞。每个活动事务因此结束;FIFO 队列中有限个前驱依次结束,每个已到达请求最终被处理。有限缓冲可能引入额外资源等待,本证明没有覆盖;可靠也不等于存在固定网络延迟上界。

协议本体保存 O(1+N) 个缓存/目录状态和在途控制记录。每个缓存只有一个应用 pending,即使它在旧 Installed 回程时发出新请求,也只多出当前事务的有限确认;不会在固定 N 下无界堆积未完成请求。一次共享撤销要枚举 s 个目标,消息数为 2s+3;脏交接是5条。这是消息账,不能直接等同于程序运行时间。

完整参考器用 deque 实现 home 队列,但为任意选取交付顺序,把网络保存为列表。删除列表中间一项最坏 O(1+N);每个事件还开启全缓存与在途载体检查,最坏同阶。因此实际参考器的单事件最坏为 O(1+N),有 s 个撤销者的完整远程事务为 O((s+1)(N+1))。日志另占已完成操作数 E 的 O(E) 空间;可见状态快照复制整个日志,另花 O(1+N+E)。这里按固定大小数据和身份记操作,任意精度整数需另计位成本。

程序的 V 字段、完整日志和故意破坏步骤的测试都用于核验,不参与授权对象、数据来源或消息路由的选择。小规模穷举与随机调度提供具体证据;一般正确性仍来自上述状态不变量和明确的网络条件。

参考资料
  • Vijay Nagarajan, Daniel J. Sorin, Mark D. Hill, David A. Wood, A Primer on Memory Consistency and Cache Coherence, 2nd ed., 2020,§§8.1–8.2.6,印刷 pp.151–161(含封面 PDF pp.173–183):目录、失效确认及瞬态;表8.1–8.2给出教材基线的完整控制器规则。本文另外选择单块串行到 Installed、数据经 home 返回的保守模型,并独立列出其完整规则与证明,没有照搬教材的并发优化表。
  • 同书 §8.7.3,印刷 pp.180–182(PDF pp.202–204):去掉转发网络点到点顺序会引入的竞争,以及额外握手这一处理方向。本页依靠安装确认与串行处理允许任意消息乱序;无界缓冲是另外声明的简化,不能拿来证明真实有限互连无死锁。
关系图谱5 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系

使用的工具