ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C++多线程并发学习路线

C++多线程并发学习路线 并发 (Concurrency)是指同时管理多个任务的能力这些任务可以交替执行。第一阶段标准库基础 (C11)这是起点你需要熟悉thread库。核心概念什么是线程主线程与子线程的关系。APIstd::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的区别。补充C17 scoped_lock支持同时获取多个锁第三阶段异步与高级抽象 (C11/14/17)有时候你不需要管理原始线程只需要结果。Future/Promisestd::future,std::promise,std::packaged_task。 promise写值写异常。 future读值或抛出异常。packaged_task把可调用对象包装成一个异步任务内部有一个 promise。自动异步std::async(最简单的多线程启动方式返回值为std::future类型)。基于线程(std::thread)的并发和基于任务(std::async)的并发第四阶段实战与架构 (设计模式)线程池 (Thread Pool)避免频繁创建销毁线程的开销。死锁 (Deadlock)如何避免多个锁互相等待。C20 新特性std::jthread(自动 join),std::latch,std::barrier。注意在实际生产中很少直接用std::thread启动任务而是用线程池。这里有一个视频讲得不错基于C11实现的异步线程池【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×864 个线程争抢 CPU 反而比单线程更慢。3. 瓶颈在磁盘 I/O 而非 CPU 如果图片很大主要耗时在磁盘读写多线程并行写盘会导致 磁头频繁寻道 HDD或 SSD 写入带宽争用性能不升反降。
返回列表