# MOESI 协议 —— 增加 Owned 状态，允许"脏且共享"（AMD）

> MOESI 在 [MESI](/concepts/cache/mesi.md) 基础上加了 **O(Owned)** 状态。核心优化：让一行**既是脏的（比内存新）、又能被多个核共享**，从而**跨核传数据时不必先写回内存**。AMD 处理器（含 Infinity Fabric 互联）采用这一族。


> 家族起点见 [msi.md](/concepts/cache/msi.md)，横向对比见 [comparison.md](/concepts/cache/comparison.md)。

## 一、五种状态

| 状态 | 全称 | 和内存一致? | 可有其他副本? | 谁负责供数/写回 |
|------|------|:---:|:---:|------|
| **M** | Modified | 否（脏）| 否 | 本核 |
| **O** | **Owned** | **否（脏）** | **是** | **本核（唯一 Owner）** |
| **E** | Exclusive | 是 | 否 | — |
| **S** | Shared | 见下 | 是 | — |
| **I** | Invalid | — | — | — |

**O 是 MOESI 的灵魂**：它表示"这行是脏的（比内存新），但我允许别的核也持有共享副本，而我作为 **Owner** 负责在需要时把最新数据供给它们、并最终负责写回内存"。

> 注意 MOESI 里 **S 的语义放宽了**：MESI 的 S 一定和内存一致（干净）；MOESI 的 S 副本可能对应一个处于 O 的脏主本——即 S 可能"脏"，但持有者不负责写回，写回责任在那个 O。

## 二、O 状态解决了什么：省掉写回内存

对比"核 A 改过某行（M），核 B 现在要读"：

```plantuml
@startuml
skinparam shadowing false
skinparam sequence {
  ParticipantBackgroundColor #E3F2FD
  ParticipantBorderColor     #1976D2
  ArrowColor                 #6A1B9A
  LifeLineBorderColor        #90A4AE
}
participant "核A" as A
participant "内存" as MEM
participant "核B" as B
== MESI：M 被读时必须写回内存 ==
B -> A  : ① BusRd（我要读）
A -> MEM : ② Flush：把脏数据写回内存
A -> B  : ③ 供数，双方降为 Shared(干净)
note over A, MEM : 多一次写内存
== MOESI：M→O，直接转发，不写内存 ==
B -> A  : ① BusRd
A -> B  : ② 直接把脏数据转发给 B（cache-to-cache）
A -> A  : ③ 自己变 Owned（仍是脏，负责将来写回）
B -> B  : ④ 变 Shared
note over A, B : 省掉写内存；写回推迟到 Owner 被驱逐时
@enduml
```

在多核频繁**读被别人改过的数据**（生产者-消费者、共享数据结构）的场景，MOESI 靠 cache-to-cache 转发 + 延迟写回，显著减少内存带宽压力——这对内存带宽紧张的多核服务器很关键。

## 三、状态机（PlantUML）

只画出与 MESI 的关键差异部分（M/E/S/I 的本核迁移同 [mesi.md](/concepts/cache/mesi.md)）：

```plantuml
@startuml
skinparam shadowing false
hide empty description
skinparam state {
  BackgroundColor<<m>> #FFCDD2
  BorderColor<<m>>     #C62828
  BackgroundColor<<o>> #FFE0B2
  BorderColor<<o>>     #EF6C00
  BackgroundColor<<e>> #BBDEFB
  BorderColor<<e>>     #1976D2
  BackgroundColor<<s>> #C8E6C9
  BorderColor<<s>>     #388E3C
  BackgroundColor<<i>> #EEEEEE
  BorderColor<<i>>     #757575
}
state "Modified"  as M <<m>>
state "Owned"     as O <<o>>
state "Shared"    as S <<s>>
state "Exclusive" as E <<e>>
state "Invalid"   as I <<i>>
M --> O  : 嗅探到 BusRd\n(转发脏数据给读者，自己成 Owner，不写内存)
O --> O  : 嗅探到 BusRd\n(继续给新读者转发)
O --> M  : PrWr\n(先 BusUpgr 让其他 S 失效，重新独占)
O --> I  : 嗅探到 BusRdX\n(有人要写，转发后失效)
E --> M  : PrWr (独占静默升级，同 MESI)
S --> M  : PrWr (BusUpgr)
note right of O
  Owned = 脏 + 可共享 + 我负责写回
  这是 MESI 没有的
end note
@enduml
```

## 四、MESI vs MOESI：一句话区别

- **MESI**：一行要么"脏且独占(M)"，要么"干净可共享(S)"。**脏的行被别人读时，必须先写回内存**，才能变共享。
- **MOESI**：允许"脏且共享(O + 其他核 S)"。**脏的行被别人读时，Owner 直接转发、不写内存**，写回推迟到 Owner 这行被驱逐时。

省下的就是那一次（乃至多次）到内存的写。

## 五、谁在用

- **AMD** 系列处理器（Opteron 以来，直到 Zen 的 Infinity Fabric）主要采用 MOESI 族。
- 优势场景：核多、共享脏数据频繁、内存带宽是瓶颈时，cache-to-cache 转发比反复读写内存高效。

> 对开发者的实际影响：无论 MESI 还是 MOESI，**伪共享的规避手段完全一样**（cache line 对齐/填充，见 [mesi.md](/concepts/cache/mesi.md) 第五节）——协议变种优化的是硬件内部的数据流转，不改变"变量别挤同一 cache line"这条应用层准则。

## 六、和本仓库其他文档

> 起点 [msi.md](/concepts/cache/msi.md)；主协议 [mesi.md](/concepts/cache/mesi.md)；Intel 变种 [mesif.md](/concepts/cache/mesif.md)；写更新族 [dragon.md](/concepts/cache/dragon.md)；对比 [comparison.md](/concepts/cache/comparison.md)；观测 `perf c2c` 见 [mesi.md](/concepts/cache/mesi.md) 第六节。
