news 2026/9/3 11:35:58

Linux C/C++ 学习日记(49):线程池

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux C/C++ 学习日记(49):线程池

注:该文用于个人学习记录和知识交流,如有不足,欢迎指点。

一、线程池是什么?

  • 进程是操作系统进行资源分配的基本单位,线程是操作系统进行CPU调度的基本单位。
  • 线程池是维持管理一定数量线程的池式结构:
  • 维持就是复用、
  • 管理就是控制线程工作和休眠,
  • 一定数量是因为CPU核心数有限(线程池过多会增加CPU切换)

总的来说:线程池(Thread Pool)是一种预先创建一组可复用线程的资源管理机制,核心是维护一个线程集合,将任务提交到线程池后,由池中的空闲线程执行,避免频繁创建 / 销毁线程的开销,同时统一管理线程的生命周期

二、线程池解决的问题

异步执行耗时任务(不过度占用核心线程),充分利用多核。

耗时:

  • 耗时等待(io):如落盘操作、向数据库请求数据
  • 耗时计算:如加解密运算等

三、线程池是如何实现的呢?

在 C++ 中

可基于以下同步原语实现

  • std::thread:线程
  • std::mutex:互斥锁
  • std::condition_variable:条件变量

也可使用第三方库(如 Boost.ThreadPool)。

实现模板

  1. 生产消费模型:任务队列
  2. 生产者push任务到队列,唤醒一个休眠线程
  3. 消费者从任务队列里面取任务去执行
  4. 任务队列里面没有任务的话消费者会陷入休眠(线程阻塞)

问1:为什么采用队列?

  • 职责:生产者对应着一个口、消费者对应着另一个口
  • 队列的插入和读取O(1) 、 锁占用的时间短 、 锁的使用变得灵活

问2:线程池中的线程数量如何确定

  • cpu密集型:
    经验值:cpu核心数个线程数量。
    最优值:经验值+1、+2比对性能得到
  • io密集型:
    (线程等待时间+cpu运算时间)*cpu核心数/cpu运算时间
    经验值:2*cpu核心数个线程数量(一半等待、一半执行)。
    最优值:经验值+1、+2 比对性能得到
  • 性能测试(吞吐量):每秒执行的任务数量

问3:线程池的设计关键?

关键在于队列的设计和线程数量的管理。

1. 队列的设计

队列设计维度对应的线程池类型核心影响
队列边界(有界 / 无界)有界任务队列线程池 / 无界队列池决定任务积压时的行为(阻塞 / 拒绝 / 溢出)
队列排序规则普通 FIFO 池 / 优先级线程池决定任务执行的优先级(如 VIP 订单优先)
队列时间属性普通池 / 定时 / 延迟线程池决定任务是否支持延迟 / 周期性执行
队列数据结构普通队列池 / 批量任务池决定是否支持任务批量提取 / 执行
队列的数量生产者一个队列、消费者一个队列通过一次队列的交换减少了锁的竞争

tips:FIFO (First In, First Out) : 先进先出

举个典型例子:

  • 「优先级线程池」和「普通固定线程池」的核心差异,就是队列从std::queue(FIFO)换成了std::priority_queue(按优先级排序),线程数管理(固定)完全相同;
  • 「定时线程池」的核心改造也是队列 —— 将普通队列替换为「按执行时间排序的优先级队列」,线程会定时检查队列头部任务是否到执行时间;
  • 「有界任务队列线程池」和「无界固定线程池」的唯一差异,就是队列设置了最大容量,队列满时提交任务的线程会阻塞 / 拒绝任务。

2. 线程数量的管理

基础线程池类型核心区分依据(线程数量管理)
固定线程池线程数初始化后固定,永不增删
缓存线程池线程数动态增减(无核心线程,空闲超时销毁)
单线程池线程数固定为 1,任务串行执行

四、代码实现:

关键知识点

1. lock_guard与unique_lock

  • lock_guard 无法手动释放锁
  • unique_lock 可以手动释放锁


2. std::condition_variable not_empty_;

  • not_empty_.wait(lock, condi_func):释放锁,然后休眠,等待唤醒判断条件是否满足 (满足则获取锁,否则继续休眠)
  • not_empty_.notify_one(): 唤醒wait中的一个线程
  • not_empty_.notify_all() :唤醒wait中的所有线程,常用于销毁线程池

核心代码:

1. 固定线程池

threadpool.h
#pragma once #include <thread> #include <functional> #include <vector> // #include "blockingqueue.h" //避免循环依赖(头文件扩散)!!!!!,只在源文件中引用 // 前置声明 // blockingqueue 仅仅只能用作指针或引用 template <typename T> class BlockingQueue; class ThreadPool { public: // 初始化线程池 explicit ThreadPool(int threads_num); // 停止线程池 ~ThreadPool(); // 发布任务到线程池 void Post(std::function<void()> task); private: void Worker(); std::unique_ptr<BlockingQueue<std::function<void()>>> task_queue_; // 拷贝构造会报错 --> 防止外部调用拷贝构造 std::vector<std::thread> workers_; };
threadpool.cc
#include "blockingqueue.h" #include <memory> #include "threadpool.h" ThreadPool::ThreadPool(int threads_num) { task_queue_ = std::make_unique<BlockingQueue<std::function<void()>>>(); for (size_t i = 0; i < threads_num; ++i) { workers_.emplace_back([this] {Worker();}); } } // 停止线程池 ThreadPool::~ThreadPool() { task_queue_->Cancel(); for(auto &worker : workers_) { if (worker.joinable()) worker.join(); } } void ThreadPool::Post(std::function<void()> task) { task_queue_->Push(task); } void ThreadPool::Worker() { while (true) { std::function<void()> task; if (!task_queue_->Pop(task)) { break; } task(); } }

2. 队列的设计

blockingqueue.h

2.1. 单队列

生产者和消费者共用一个队列,意味着锁的竞争频繁

#pragma once #include <condition_variable> #include <functional> #include <queue> #include <mutex> #include <thread> template <typename T> class BlockingQueue { public: BlockingQueue(bool nonblock = false) : nonblock_(nonblock) { } // 入队操作 void Push(const T &value) { std::lock_guard<std::mutex> lock(mutex_); queue_.push(value); not_empty_.notify_one(); // 唤醒 not_empty_.wait(lock, [this]{ return !queue_.empty() || nonblock_; });处的worker } // 正常 pop 弹出元素 // 异常 pop 没有弹出元素 bool Pop(T &value) { std::unique_lock<std::mutex> lock(mutex_); // 1. mutex_.unlock() // 2. queue_empty && !nonblock 线程在 wait 中阻塞 // notify_one notify_all 唤醒线程 // 3. 假设满足条件 mutex_.lock() // 4. 不满足条件 回到 2 not_empty_.wait(lock, [this]{ return !queue_.empty() || nonblock_; }); // 线程休眠 if (queue_.empty()) return false; value = queue_.front(); queue_.pop(); return true; } // 解除阻塞在当前队列的线程 void Cancel() { std::lock_guard<std::mutex> lock(mutex_); nonblock_ = true; not_empty_.notify_all(); } private: bool nonblock_; std::queue<T> queue_; std::mutex mutex_; std::condition_variable not_empty_; };
2.2 双队列

生产者一个队列、消费者一个队列

#pragma once #include <condition_variable> #include <functional> #include <queue> #include <mutex> #include <thread> template <typename T> class BlockingQueuePro { public: BlockingQueuePro(bool nonblock = false) : nonblock_(nonblock) {} void Push(const T &value) { std::lock_guard<std::mutex> lock(prod_mutex_); prod_queue_.push(value); not_empty_.notify_one(); } bool Pop(T &value) { std::unique_lock<std::mutex> lock(cons_mutex_); if (cons_queue_.empty() && SwapQueue_() == 0) { return false; } value = cons_queue_.front(); cons_queue_.pop(); return true; } void Cancel() { std::lock_guard<std::mutex> lock(prod_mutex_); nonblock_ = true; not_empty_.notify_all(); } private: int SwapQueue_() { std::unique_lock<std::mutex> lock(prod_mutex_); not_empty_.wait(lock, [this] {return !prod_queue_.empty() || nonblock_; }); std::swap(prod_queue_, cons_queue_); return cons_queue_.size(); } bool nonblock_; std::queue<T> prod_queue_; std::queue<T> cons_queue_; std::mutex prod_mutex_; std::mutex cons_mutex_; std::condition_variable not_empty_; };
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 15:14:49

GSE插件宏编辑终极指南:版本升级完整教程

GSE插件宏编辑终极指南&#xff1a;版本升级完整教程 【免费下载链接】GSE-Advanced-Macro-Compiler GSE is an alternative advanced macro editor and engine for World of Warcraft. It uses Travis for UnitTests, Coveralls to report on test coverage and the Curse pac…

作者头像 李华
网站建设 2026/9/3 4:02:56

DeepSeek-V3推理性能实战调优:从延迟瓶颈到吞吐量巅峰

你是否曾经在深夜盯着监控面板&#xff0c;看着P99延迟曲线不断攀升而束手无策&#xff1f;或者面对昂贵的GPU集群&#xff0c;却发现利用率始终无法突破60%&#xff1f;这些正是大模型推理优化中最常见的痛点。本文将带你深入DeepSeek-V3的性能调优实战&#xff0c;帮你找到那…

作者头像 李华
网站建设 2026/9/3 4:59:25

时间序列数据增强实战:5大技巧让模型性能飙升200%

还在为时间序列数据样本不足而头疼吗&#xff1f;&#x1f914; 作为技术决策者和一线开发工程师&#xff0c;我们都知道数据质量直接影响模型效果。今天就来聊聊Time-Series-Library项目中那些让模型性能翻倍的数据增强黑科技&#xff01; 【免费下载链接】Time-Series-Librar…

作者头像 李华
网站建设 2026/9/2 10:08:12

Wan2.1 GP 视频生成工具完全使用指南

Wan2.1 GP 视频生成工具完全使用指南 【免费下载链接】Wan2GP Wan 2.1 for the GPU Poor 项目地址: https://gitcode.com/gh_mirrors/wa/Wan2GP Wan2.1 GP 是一款专为消费级GPU优化的开源视频生成工具&#xff0c;它让普通用户也能轻松制作AI视频。无论你是内容创作者、…

作者头像 李华
网站建设 2026/9/3 0:03:35

零门槛部署Lucky:让你的设备轻松拥有公网访问能力

零门槛部署Lucky&#xff1a;让你的设备轻松拥有公网访问能力 【免费下载链接】lucky 软硬路由公网神器,ipv6/ipv4 端口转发,反向代理,DDNS,WOL,ipv4 stun内网穿透,cron,acme,阿里云盘,ftp,webdav,filebrowser 项目地址: https://gitcode.com/GitHub_Trending/luc/lucky …

作者头像 李华