冒险 (计算机系统结构)

冒险（hazard）又稱作-{zh-hant:冒險; zh-hans:危障;}-或险象，是指在计算机CPU的微体系结构中，指令管線化乱序执行中的一些问题可能会导致得到不正确的计算结果。有3类典型的冒险：
 数据冒险
 结构冒险
 控制冒险（分支冒险）

有几种方法用于应对这些风险，如流水线停顿（流水线氣泡），寄存器直通等待。

背景

指令在一个流水线处理器中的执行被分为若干阶段，因此在一个时刻有多条指令处于流水线的不同阶段上被处理。如取操作数、执行等等。Intel的Pentium就是处理器流水线。有的处理器进一步是指令乱序执行，如Intel的Pentium Pro开创的Intel P6微体系结构。指令的乱序执行就会引入一些危险的情况。

类型

数据冒险
指令乱序执行时，可能会发生读取数据与写入数据之间的时序与空间的相关性，成为数据冒险。如果不加以处理，可能会导致竞态条件。 有3种可能的数据冒险：

 先写后读（RAW），这是真实的相关。
 先读后写（WAR），被称为反相关。
 写后写（WAW），被称为输出相关。
以下為先寫後讀（RAW）的範例：

i1. R2 <- R1 + R3 
i2. R4 <- R2 + R3

第一个指令是计算一个值，并将其储存在R2，而第二个指令是使用这个值计算结果并储存在R4，但是在我们拿出第二步的操作数时，第一步的结果还未被储存。因此我们具有一种数据相关性。
我们可以说那有 一种数据依赖性对于指令i2，他依赖于指令i1的完成。

结构冒险
结构冒险是指多条指令同时要访问处理器一处硬件。典型例子是一个存储单元被一条指令取操作数同时另一条指令要写入结果。

控制冒险

又稱分支冒险，指令流水时，处理器遇到分支指令，不能在流水开始阶段就判断出分支结果。

去除冒险

一般办法

流水线汽泡  
流水线汽泡，也称作流水线停顿，可以同时解决上述3种冒险。指令译码时如果控制器发现可能存在冒险，就插入NOP（No Operation）指令。这样在有风险的指令进入流水线时，上一条指令已经在流水线中经过了充分多的周期，从而化解了冒险。如果插入的NOP的数量等于流水线的级数，那么处理器就排空了整个流水线。这被称为冲刷流水线（flushing the pipeline）。

数据冒险
有几种方案与算法解决数据冒险。

 在先写后读时，在写指令与读指令之间插入流水线汽泡。
 使用乱序执行，通过寄存器重命名保证了先写后读的数据相关被顺序执行，而对另外两种反相关、输出相关的情况的实现了“去相关”后的并发执行。
 利用寄存器直通（register forwarding，或稱转发机制）来使用流水线的最新的计算结果。

控制风险
避免控制风险的办法：
 在分支指令后插入流水线汽泡，直到分支指令的流水执行完毕。
 使用分支预测，然后投机执行。如果分支预测失败，则要有能力恢复到分支指令执行完毕时刻的寄存器状态，进入正确的分支继续执行。

参见 
 寄存器重命名、Tomasulo算法
 数据-程序依赖
 乱序执行
 分支预测
 分支预测器

参考文献
 
  David Andrew Patterson, John L. Hennessy Computer Organization and Design (4 ed.), Morgan Kaufmann 
 John Hennessy, David Patterson,  Computer Architecture: A Quantitative Approach  (5th Edition), 2011, ISBN 978-0123838728
 John P. Shen and Mikko H. Lipasti, Modern Processor Design: Fundamentals of Superscalar Processors, 2004, ISBN 0070570647

电脑架构