从 C++ 基础到掌握 — 第 23 集
通过构建、测试、Sanitizer 和性能分析完成精通项目
本博客文章以教学为目的编写。 内容可能存在错误,请结合目标编译器和标准库文档进行确认。
精通不是堆满高级语法,而是能用可复现证据说明需求、生命周期、失败和性能。最终项目把整个系列整合为异步资源流式加载系统。
Capstone 契约
request → 去重 → 读文件 → decode → GPU upload → cache
│ │ │
取消/错误 worker pool 主线程边界
- 同一资源键的并发请求共享一个操作。
- 所有等待者都取消时停止不必要工作。
- 文件 bytes、decode buffer 和 GPU 对象有明确所有者。
- Worker 结束后 callback 不得访问已销毁状态。
- 保留错误类别以及是否可重试。
- 用代表性 workload 测量时间、内存和分配目标。
让依赖向内
include/streaming/ 公开契约、handle、错误类型
src/core/ 状态机与去重
src/io/ 文件系统 adapter
src/decode/ 图像 decoder adapter
src/gpu/ render-thread adapter
tests/ 单元、集成与 race 测试
benchmarks/ 可复现 workload
核心状态机不直接依赖图形 API 或文件系统,而是接收小型接口或受约束类型,测试注入可控制顺序的 fake。
Header 中的 inline 函数和模板必须在每个 translation unit 中保持等价定义。修改公开对象 layout 或虚函数顺序可能破坏 ABI,因此 shared library 边界需要版本与重建策略。
用工具复现失败
-fsanitize=address,undefined -fno-omit-frame-pointer
-fsanitize=thread
AddressSanitizer 帮助查找生命周期和越界错误,UndefinedBehaviorSanitizer 报告多类 undefined behavior,ThreadSanitizer 查找 data race。ASan 与 TSan 通常使用不同构建,平台支持也不同。
必要失败测试包括空文件、损坏数据、取消与完成竞争、重复请求、worker 关闭以及 allocator 耗尽。使用 barrier、fake executor 和可控 callback,不要依赖 sleep。
Profile 用于验证假设
记录 CPU、OS、编译器版本和选项、输入、命令、重复次数与原始结果。除了平均值,还要查看 p50/p95 latency、peak memory、分配次数和吞吐量。
从 profile 选择一个瓶颈,一次只改变一项,再比较正确性与资源。std::move、自定义 allocator 和 lock-free 结构都需要证据。
完成条件
- 用图说明所有权和 thread affinity。
- 每项工作都有成功、失败、取消和关闭路径。
- 用自动测试与 Sanitizer 检查 race 和生命周期错误。
- 从干净环境复现 configure、build、test。
- 用 ADR 保存前后数据、舍弃方案和限制。
精通 C++ 不是背下语言的所有角落,而是用类型表达值和资源生命周期,控制并发与失败边界,并根据编译器、测试、Sanitizer 与 profiler 的证据持续修正设计。