☰
C++多线程并发学习路线
2026/9/29 7:50:44 网站建设 项目流程

并发 (Concurrency)是指同时管理多个任务的能力,这些任务可以交替执行。

第一阶段:标准库基础 (C++11)

这是起点,你需要熟悉<thread>库。

  • 核心概念:什么是线程?主线程与子线程的关系。

  • API:std::thread的创建、join()(等待线程结束)、detach()(分离线程)。

  • 生命周期:理解如果std::thread对象销毁前没有 join 或 detach 会导致程序崩溃 (terminate)。

  • 补充:thread_local关键字。

第二阶段:同步与互斥 (数据安全)

多线程最难的地方不是开启线程,而是如何安全地访问共享数据。如果不加控制,就会发生竞态条件 (Race Condition)。

  • 互斥锁:std::mutex。

  • RAII 锁管理(必须掌握):永远不要手动lock()和unlock(),要使用std::lock_guard和std::unique_lock。

  • 条件变量:std::condition_variable,用于线程间的通信(例如:生产者-消费者模型)

  • 原子操作:std::atomic(解决共享数据的原子性访问和内存可见性。对于简单的整数加减,比锁快得多)。

  • 注意:std::lock_guard和std::unique_lock的区别。

  • 补充:C++17 scoped_lock,支持同时获取多个锁

第三阶段:异步与高级抽象 (C++11/14/17)

有时候你不需要管理原始线程,只需要结果。

  • Future/Promise:std::future,std::promise,std::packaged_task。( promise写值,写异常。 future读值,或抛出异常。packaged_task把可调用对象包装成一个异步任务,内部有一个 promise。)

  • 自动异步:std::async(最简单的多线程启动方式,返回值为std::future类型)。

  • 基于线程(std::thread)的并发和基于任务(std::async)的并发:

第四阶段:实战与架构 (设计模式)

  • 线程池 (Thread Pool):避免频繁创建销毁线程的开销。

  • 死锁 (Deadlock):如何避免多个锁互相等待。

  • C++20 新特性:std::jthread(自动 join),std::latch,std::barrier。

注意,在实际生产中,很少直接用std::thread启动任务,而是用线程池。这里有一个视频讲得不错:

基于C++11实现的异步线程池【C/C++】_哔哩哔哩_bilibili

## 线程池是否有必要?
### ✅ 有必要的情况
1. 存在并发图片流 如果有多张图片持续涌入(比如相机连拍、多路摄像头同时上传),线程池能让它们 并行处理 ,充分利用多核 CPU。

2. 处理耗时较长`cv::resize` + JPEG 编码是 CPU 密集型操作。如果单张处理需要几十毫秒,串行处理会造成积压,线程池能提升整体吞吐量。

3. 需要削峰填谷 图片到达是突发的,但处理是匀速的。线程池 + 任务队列可以 缓冲峰值 ,避免瞬时压力打满 CPU。

### ❌ 没必要的情况
1. 图片是串行到达的 如果一次只处理一张,处理完才来下一张,线程池和单线程效果一样,反而多了线程切换开销。

2. OpenCV 内部已多线程,造成过度订阅 这是最容易被忽略的点。OpenCV 的`cv::resize` 、`cv::imwrite` 等函数 内部已经使用多线程 (TBB/OpenMP)。如果外层线程池开 8 个线程,每个线程里 OpenCV 又开 8 个线程,就是 8×8=64 个线程争抢 CPU ,反而比单线程更慢。

3. 瓶颈在磁盘 I/O 而非 CPU 如果图片很大,主要耗时在磁盘读写,多线程并行写盘会导致 磁头频繁寻道 (HDD)或 SSD 写入带宽争用,性能不升反降。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询