C++ Concurrency in Action - 第2版

基本信息

  • 作者: Anthony Williams
  • 出版社: Manning
  • 页数: 592页
  • 版本: 第二版(C++17)
  • ISBN: 9781617294693

核心主题

1. 并发基础(第1章)

  • 并发 vs 并行: 并发是关于多个任务同时处理,并行是真正同时在多核上执行
  • 两种方法:
    • 多进程:独立地址空间,通信开销大但更安全
    • 多线程:共享地址空间,开销小但需要手动同步
  • 使用并发的理由:
    • 关注点分离(如UI线程与计算线程分离)
    • 性能提升(任务并行和数据并行)
  • 何时不用并发: 成本>收益,上下文切换开销,资源限制

2. 线程管理(第2章)

  • std::thread 基本用法
  • 线程参数传递(引用需用 std::ref)
  • 线程所有权转移
  • 动态选择线程数量
  • 线程标识

3. 共享数据保护(第3章)

  • 竞态条件: 多个线程访问共享数据导致的未定义行为
  • 互斥锁:
    • std::mutex
    • std::lock_guard - RAII锁
    • std::unique_lock - 更灵活的锁
    • std::scoped_lock(C++17)- 多锁加锁防死锁
  • 死锁避免:
    • std::lock / std::try_lock
    • 始终按固定顺序获取锁
    • 使用 RAII 确保锁释放
  • 精细粒度锁定: 按数据分离而非按锁分离

4. 操作同步(第4章)

  • 条件变量:
    • std::condition_variable
    • notify_one() / notify_all()
    • wait() / wait_for() / wait_until()
  • Future/Promise:
    • std::future / std::shared_future
    • std::promise / std::packaged_task
    • std::async - 异步任务
  • 超时机制:
    • std::chrono 时钟、持续时间、时间点
  • Continuations(Concurrency TS):
    • then() 链式处理
    • when_all() / when_any()

5. 内存模型与原子操作(第5章)- 核心难点

  • 内存序:
    • memory_order_relaxed - 只保证原子性
    • memory_order_consume - 依赖同步
    • memory_order_acquire - 获取操作
    • memory_order_release - 释放操作
    • memory_order_acq_rel - 获取+释放
    • memory_order_seq_cst - 顺序一致(默认)
  • synchronizes-with 关系
  • happens-before 关系
  • Release sequences
  • Fences: std::atomic_thread_fence

6. 基于锁的并发数据结构(第6章)

  • 线程安全栈
  • 线程安全队列(条件变量 + 锁)
  • 细粒度锁队列
  • 线程安全查找表
  • 线程安全列表

7. 无锁并发数据结构(第7章)

  • 非阻塞数据结构分类:
    • Lock-free: 至少一个线程总能进展
    • Wait-free: 所有线程都能在有限步内完成
  • 内存回收问题:
    • Hazard Pointers
    • Reference Counting
    • Epoch-based Reclamation
  • ABA问题: 用版本戳或标签指针解决
  • 指导原则:
    • 原型用 seq_cst
    • 使用无锁内存回收方案
    • 识别忙等循环并帮助其他线程

8. 并发代码设计(第8章)

  • 工作划分:
    • 数据分区(预处理前)
    • 递归数据分割
    • 按任务类型划分
  • 性能影响因素:
    • 处理器数量
    • 数据争用与缓存ping-pong
    • False Sharing(假共享): 用 alignas 和 hw_destructive_interference_size 避免
    • 数据局部性
    • 超配与过度任务切换
  • 可扩展性: Amdahl定律
  • 并行算法实现:
    • 并行 std::for_each
    • 并行 std::find
    • 并行 std::partial_sum

9. 高级线程管理(第9章)

  • 线程池:
    • 基本线程池
    • 等待任务完成
    • 任务间等待
    • 避免工作队列竞争
    • Work Stealing(工作窃取)
  • 中断线程:
    • 主动中断
    • 检测中断
    • 中断条件变量等待
    • 应用程序退出时中断后台任务

10. 并行算法(第10章)

  • 执行策略:
    • std::execution::seq - 顺序
    • std::execution::par - 并行
    • std::execution::par_unseq - 并行未排序
  • C++17 标准库并行算法
  • std::reduce 替代 std::accumulate

11. 测试与调试(第11章)

  • 并发Bug类型:
    • 意外阻塞
    • 竞态条件
  • 定位技术:
    • 代码审查
    • 测试定位
    • 可测试性设计
  • 多线程测试技术:
    • 暴力测试
    • 组合模拟测试
    • 使用特殊库检测问题
  • 性能测试

关键概念速查

概念说明
RAII资源获取即初始化,用于自动锁管理
memory_order原子操作的内存序,控制可见性和排序
False Sharing不同线程访问同一缓存行的不同变量导致性能下降
Work Stealing空闲线程从其他线程工作队列偷取任务
ABA问题无锁结构中指针值恢复导致逻辑错误
Hazard Pointer无锁内存回收方案,标记正在使用的节点

实践要点

  1. 优先使用高级抽象: mutex、future、parallel algorithm
  2. 低层优化才用原子: 仅在高性能关键路径使用
  3. 测试并发代码: 并发Bug难以复现,需要专门测试策略
  4. 注意数据局部性: 避免跨核缓存传输
  5. 线程数 = 核心数: 通常最优,过多反而降低性能

与其他知识关联