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::mutexstd::lock_guard- RAII锁std::unique_lock- 更灵活的锁std::scoped_lock(C++17)- 多锁加锁防死锁
- 死锁避免:
std::lock/std::try_lock- 始终按固定顺序获取锁
- 使用 RAII 确保锁释放
- 精细粒度锁定: 按数据分离而非按锁分离
4. 操作同步(第4章)
- 条件变量:
std::condition_variablenotify_one()/notify_all()wait()/wait_for()/wait_until()
- Future/Promise:
std::future/std::shared_futurestd::promise/std::packaged_taskstd::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 | 无锁内存回收方案,标记正在使用的节点 |
实践要点
- 优先使用高级抽象: mutex、future、parallel algorithm
- 低层优化才用原子: 仅在高性能关键路径使用
- 测试并发代码: 并发Bug难以复现,需要专门测试策略
- 注意数据局部性: 避免跨核缓存传输
- 线程数 = 核心数: 通常最优,过多反而降低性能
与其他知识关联
- Effective Modern C++ - C++11/14特性实践
- Modern Cpp Design - Policy-Based Design与并发结合
- C++ Concurrency in Action - 第一版笔记(第361次运行)