Skip to content

L17:事务内存(Transactional Memory

MIT 6.5900 Fall 2024 · Daniel Sanchez(基于 Christos Kozyrakis 的幻灯片) 主题:并行编程之难、并发控制、事务内存(TM)语义、数据版本管理与冲突检测、硬件事务内存(HTM


一、动机:并行编程很难

多核的理由是性能/成本曲线:与其一个高性能高成本的核,不如用多个适中而高效的核。但并行编程很难:

  • 把算法划分为任务;
  • 把任务映射到线程;
  • 加同步(锁、屏障……)以避免数据竞争并保证任务顺序;
  • 陷阱:可扩展性、局部性、死锁、活锁、公平性、竞争、可组合性、可移植性……

例:哈希表

顺序实现的 lookup 非线程安全(并发 insert 与 lookup 会竞争),需要同步。

  • 粗粒度锁:给所有方法加 lock/unlock问题:把对互不相关的桶的操作也串行化了;
  • 细粒度锁:每桶一把锁。问题:加锁开销大,且仍过度串行化(如对同一桶的并发只读也被串行)。

性能:在平衡树与哈希表两种负载下,细粒度锁通常优于粗粒度锁,但都难以随处理器数线性扩展。


二、并发控制(Concurrency Control

为避免共享数据上的竞争,两类思路:

  • 停顿(Stall)/ 互斥:保证临界区内至多一个进程,其余等待;
  • 推测(Speculate)
    • :假设临界区内不会冲突;
    • :检测是否发生冲突的数据访问;
    • 恢复:若冲突则回滚,否则提交。

三、事务内存(TM)

内存事务memory transaction,[Lomet'77, Knight'86, Herlihy & Moss'93]):一段原子且隔离的内存访问序列,灵感来自数据库事务。

  • 原子性Atomicity,要么全做要么不做):提交时所有写一次性生效;中止时所有写如同未发生;
  • 隔离性Isolation):提交前其他代码看不到这些写;
  • 可串行化Serializability):事务看起来以某个单一串行顺序提交(但具体顺序不保证)。

用 TM 编程:声明式同步

程序员说做什么而非怎么做,无需声明或管理锁;系统通常通过推测实现同步,只在冲突(R-W 或 W-W)时才有性能损失。

c
// 用锁                            // 用 TM
void deposit(account, amount) {     void deposit(account, amount) {
    lock(account.mutex);                atomic {
    int t = bank.get(account);              int t = bank.get(account);
    t = t + amount;                         t = t + amount;
    bank.put(account, t);                   bank.put(account, t);
    unlock(account.mutex);              }
}                                   }

TM 的优势

  • 易用:像粗粒度锁一样易用,程序员声明、系统实现;
  • 高性能:至少不逊于细粒度锁,自动获得读-读并发与细粒度并发,性能与正确性之间无需权衡
  • 可组合性Composability):软件模块可安全可扩展地组合(嵌套事务)。

性能:硬件 TM 系统 TCC [Hammond et al., ISCA'04] 在两种负载上随处理器数扩展明显优于锁。


四、TM 实现基础

推测在不牺牲并发的前提下提供原子性与隔离性。基本要求:

  • 数据版本管理Data versioning);
  • 冲突检测与解决Conflict detection & resolution)。

实现选项:硬件 TM(HTM)、软件 TM(STM)、混合 TM(硬件加速的 STM 与双模系统)。

为什么要硬件 TM

  • 单线程 STM 性能有 2–8× 减速(短期使并行编程失去动力,长期不节能);
  • 业界已采用 HTM:Intel(自 Haswell)、IBM(POWER8+、Blue Gene、zSeries)、ARM(v9)。

五、数据版本管理策略

为并发事务管理未提交(新)已提交(旧)两个版本:

策略做法优点缺点
急切版本Eager,基于撤销日志 undo-log)直接更新内存,把旧值记入 undo log提交快中止慢
惰性版本Lazy,基于写缓冲 write-buffer)数据缓冲到写缓冲,提交时才写回内存中止快提交慢

急切版本:写 X←15 时直接改内存并把 X:10 记入 undo log;提交丢弃日志,中止时用日志恢复。 惰性版本:写 X←15 进写缓冲,内存仍是 10;提交时写回内存,中止时丢弃写缓冲。


六、冲突检测(Conflict Detection

须跟踪事务的读集(read-set,事务内读过的地址)与写集(write-set,事务内写过的地址),处理 R-W 与(常见的)W-W 冲突。

1. 悲观检测(Pessimistic

在 load/store 当时就检查冲突:

  • SW:用锁和/或版本号设软件屏障;
  • HW:通过一致性动作检查;
  • 竞争管理器contention manager)决定停顿还是中止,按优先级策略让常见情况快。

四种情形:成功;提前检测后停顿;检测到后中止重启;多事务相互中止导致无进展(无前进保证)。

2. 乐观检测(Optimistic

在事务尝试提交时才检测冲突:

  • SW:用锁/版本号校验读写集;
  • HW:用一致性动作校验写集(为写集的 Cache 行取得独占访问),冲突时优先提交中的事务,其他事务稍后可能中止;
  • 也可二者结合:不少 STM 对读乐观、写悲观

冲突检测的权衡

悲观乐观
优点早检测,少做无用功,部分中止转停顿前进保证,潜在更少冲突、更短加锁(SW)、批量通信(HW)
缺点无前进保证,某些情况下更多中止;加锁问题(SW)、细粒度通信(HW)晚检测,仍有公平性问题

七、硬件事务内存(HTM)实现

  • 数据版本管理:用 Cache —— 把写缓冲或 undo log 缓存进 Cache,用 Cache 元数据跟踪读集与写集(可在私有/共享/多级 Cache 上做);
  • 冲突检测:用缓存一致性协议 —— 一致性查找检测事务间冲突(支持侦听式与目录式一致性);
  • 中止时还须恢复寄存器状态 → 取寄存器检查点(乱序核可借助重命名表快照以极小改动支持)。

HTM 设计:每行的 R/W 位

每个 Cache 行跟踪读集与写集:

  • R 位:事务读过该数据(load 时置位);
  • W 位:事务写过该数据(store 时置位);
  • R/W 位可在字或行粒度;提交或中止时整组清除(gang-clear)。

一致性请求检查 R/W 位以检测冲突:

  • W 字的 Shared 请求 = 读-写冲突;
  • R 字的 Exclusive 请求 = 写-读冲突;
  • W 字的 Exclusive 请求 = 写-写冲突。

行格式示意:V D E Tag | R W Word1 | ... | R W WordN

示例:惰性 + 乐观 HTM(基于总线)

CPU 改动:寄存器检查点、TM 状态寄存器(状态、处理器指针等);Cache 改动:每行 R/W 位。

执行 Xbegin / Load A / Store B←5 / Load C / Xcommit

  1. 事务开始:初始化 CPU 与 Cache 状态,取寄存器检查点;
  2. Load A:必要时处理缺失,置该行 R 位
  3. Store B←5:必要时处理缺失(即使其他核有该行也先取 shared),置该行 W 位
  4. 快速两阶段提交:① 校验(对写集行请求独占访问)② 提交(整组清 R/W 位,把写集数据转为有效脏数据)。

冲突检测与中止:对读集/写集查找独占请求 → 命中则中止(作废写集、整组清 R/W 位、恢复检查点)。

HTM 的优势与挑战

优势

  • 常见情况快:零开销跟踪读写集、零开销版本管理、无数据移动的快速提交/中止、对读集持续校验;
  • 强隔离:对非事务 load/store 也检测冲突;
  • 简化多核一致性与一致性模型(如可用 HTM 实现难做的顺序一致性 SC)。

挑战

  • 性能病态:频繁竞争如何处理?HTM 是否应保证公平/优先级?
  • 容量限制:读集+写集超过 Cache 容量怎么办?
  • 虚拟化、I/O、系统调用……;
  • 混合 TM 可能两全:硬件处理常见情况但无保证(Cache 溢出、中断、syscall 时中止),中止后回退到 STM(Intel RTM 的当前思路),但 HTM 与 STM 如何良好整合仍不清楚;
  • 目前程序员采用缓慢/受限,仍须支持非 HTM 系统。

小结

  • 锁在易用性与并发度之间总有取舍;事务内存用声明式 atomic 把"做什么/怎么做"分离,提供原子性、隔离性、可串行化与可组合性;
  • 实现核心是数据版本管理(急切 undo-log / 惰性 write-buffer)与冲突检测(悲观早检 / 乐观晚检);
  • HTM 复用 Cache 做版本管理、复用一致性协议做冲突检测,以每行 R/W 位跟踪读写集,常见情况近零开销;难点在容量、虚拟化与公平性,混合 TM 是折中方向。

下一讲:VLIW