我原本以为缓存一致性协议(如MESI)只能在单个内存加载/存储指令中提供伪原子性但。如果我正在执行获取,修改,写入指令组合,单独的MESI将无法在第一条指令到最后一条指令中强制执行原子性。
但是,英特尔参考手册第3a卷第8节说:
8.1.4 LOCK操作对内部处理器高速缓存的影响
对于P6和更近期的处理器系列,如果是内存区域 在LOCK操作期间被锁定被缓存在处理器中 正在执行LOCK操作作为回写存储器 完全包含在缓存行中,处理器可能不会断言 总线上的LOCK#信号。相反,它将修改内存位置 在内部并允许它的缓存一致性机制来确保 操作以原子方式进行。此操作称为“缓存” 锁定。“缓存一致性机制自动阻止两个或 更多处理器缓存了相同的内存区域 同时修改该区域的数据。
这似乎与我的理解相矛盾,暗示LOCK指令不需要使用,因为可以使用缓存一致性吗?
答案 0 :(得分:4)
作为概念的锁定和实际的总线#lock信号之间存在差异 - 后者是实现第一个的手段之一。缓存锁定是另一个更简单,更高效的锁定。
MESI协议保证如果某一行仅由某个核心(无论是否经过修改)持有,则没有其他人拥有它。在这种情况下,您可以通过在缓存中添加简单标志来原子地执行多个操作,该标志会阻止外部监听,直到操作完成。这与锁定概念的作用具有相同的效果,因为没有其他人可以改变甚至观察中间值。
在更复杂的情况下,该行不由单个缓存保存(例如,它可以在多个缓存之间共享,或者访问可以在两个缓存行之间分割,并且只有一个在缓存中 - 方案列表通常是特定于实现的,并且可能没有被CPU制造商公开) - 在这种情况下,您可能不得不使用像公共汽车锁这样的“较重”的大炮,这通常可以保证没有人可以做任何事情共享总线上。显然这会对性能产生巨大影响,因此这可能仅在您没有其他选择时使用。在大多数情况下,简单的缓存级锁定就足够了。请注意,像英特尔TSX这样的新方案似乎以类似的方式工作,当您在缓存中工作时提供优化。
顺便说一句 - 你对单个指令的伪原子性的假设也是错误的 - 如果你引用单个内存操作(加载或存储),那么它是正确的,因为一条指令可能包含多个指令({{1}例如,没有锁定就不会是原子的)。您的引用中还出现的另一个限制是访问需要包含在缓存行中 - 即使在单个加载或存储中,分割行也不保证原子性(因为它们通常实现为稍后合并的2个内存操作)。
答案 1 :(得分:1)
阅读你给出的摘录,我发现使用LOCK-ed指令并不矛盾。例如,考虑INC
指令。如果没有LOCK
,它可以读取原始值,其缓存行处于SHARED
状态,这不会阻止同一缓存中的其他核心在存储相同的递增结果之前同时读取相同的值=数据比赛。
我解释了引用,因为每个缓存行粒度保证了数据完整性,当数据适合一个缓存行时,可能不需要额外的注意。但是,如果数据跨越两个缓存行的边界,则必须声明对它们的修改将以原子方式处理。