C++ Concurrency in Action (第2版) 笔记
原始文件: /books/c++/C++ Concurrency in Action 2nd.pdf
大小: 5.72MB
页数: 592页
作者: Anthony Williams
出版: Manning, 2019
格式: 文字版PDF
核心观点
本书是C++并发编程的权威指南,由C++标准委员会成员、Boost.Thread库原开发者编写。覆盖C++11/14/17的并发设施,从基础线程管理到高级无锁数据结构设计。
关键概念
1. 并发 vs 并行
- 并发 (Concurrency): 多个任务同时进展(逻辑上的同时)
- 并行 (Parallelism): 多个任务同时执行(物理上的同时)
- 并发可用于分离关注点(如UI响应+后台计算),并行主要用于性能提升
2. C++并发支持演进
- C++11: 首次引入标准线程库(std::thread, std::mutex, std::atomic等)
- C++14/17: 增强(std::shared_mutex, std::string_view, parallel algorithms)
- Concurrency TS: 扩展提案(latch, barrier, when_all/when_any)
3. 内存模型基础
- objects and memory locations: 对象与内存位置的区别
- modification orders: 修改顺序
- happens-before relationship: 先行发生关系
- synchronizes-with: 同步关系
4. 原子操作与内存序
- std::atomic_flag: 最简单的原子类型
- std::atomic
: 通用原子类型 - 内存序选项:
- seq_cst (默认, 最强一致性)
- acquire/release (平衡性能与正确性)
- relaxed (最弱,仅保证原子性)
- consume (特定场景)
5. 同步原语
- Mutexes: std::mutex, std::recursive_mutex, std::shared_mutex, std::timed_mutex
- Locks: std::lock_guard (RAII), std::unique_lock (灵活锁定)
- Condition Variables: std::condition_variable, std::condition_variable_any
- Futures/Promises: 异步结果传递
- std::async: 简化异步任务启动
6. 锁基数据结构设计
- 线程安全栈(基于锁)
- 线程安全队列(基于锁+条件变量)
- 细粒度锁队列
- 查找表、列表的线程安全实现
7. 无锁数据结构设计
- 定义: lock-free, wait-free, nonblocking
- 内存回收难题: ABA问题、hazard pointers、引用计数
- 无锁栈: 使用CAS操作
- 无锁队列: SPSC(单生产者单消费者)优化
- Guidelines: 用seq_cst原型,再优化到所需内存序
8. 并发代码设计原则
- 数据分割: 按数据划分任务
- 递归分割: divide and conquer
- 任务类型分割: 不同阶段不同线程
- 性能因素:
- CPU数量
- 数据竞争与缓存ping-pong
- False sharing(假共享)
- Oversubscription(超售)
- 数据局部性
9. 线程池
- 最简单线程池实现
- 等待任务完成
- 任务依赖处理
- Work stealing(工作窃取)
10. C++17并行算法
- std::execution策略
- sequenced_policy
- parallel_policy
- parallel_unsequenced_policy
- std::for_each, std::transform等并行版本
11. 多线程测试与调试
- Bug类型: 非预期阻塞、竞态条件
- 定位技术:
- 代码审查
- 测试定位
- 专门库(如TSan)
- 性能测试: 基准测试方法
可行动点
- 新项目: 直接使用std::thread, std::async, std::future替代POSIX线程
- 代码审查: 检查是否所有共享数据都有适当保护
- 性能优化: 识别并解决false sharing(使用alignas)
- 无锁探索: 对于高频访问数据结构,考虑lock-free设计
- 现代C++: 善用std::shared_mutex(读写锁)提升读多写少场景性能
- 并行算法: 对大数据集操作使用C++17并行算法
- 测试策略: 建立多线程测试框架,定期运行race detection工具
与其他知识关联
重要结论
- 原子操作是基石: 理解内存序对于正确并发编程至关重要
- RAII是朋友: 始终使用lock_guard/unique_lock管理锁
- 无锁≠更快: 需要仔细权衡,多数场景锁已足够
- 测试是关键: 并发bug难以复现,需系统化测试策略
- C++17并行算法: 对现有代码提升性能的低垂果实