[线程/C++(11)]线程池
文章目录
- 一、C++实现线程池
- 1. 头文件
- 2. 测试部分
- 二、C++11实现线程池
- 1. 头文件
- 2. 测试部分
一、C++实现线程池
1. 头文件
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include<iostream>
#include<string.h>
#include<string>
#include<pthread.h>
#include<stdlib.h>
#include<queue>
#include<unistd.h>
using namespace std;using callback = void(*)(void*);
//任务的结构体
template<typename T>
struct Task
{Task(){function = nullptr;args = nullptr;}Task(callback fun, void* args){function = fun;this -> args = (T*)args;}callback function;T* args;
};//任务队列
template<typename T>
class TaskQueue
{
public:TaskQueue(){pthread_mutex_init(&mutex,NULL);}~TaskQueue(){pthread_mutex_destroy(&mutex);}//添加任务void AddTask(Task<T> task){pthread_mutex_lock(&mutex);queue.push(task);pthread_mutex_unlock(&mutex);}void AddTask(callback fun, void* args){pthread_mutex_lock(&mutex);Task<T> task(fun,args); queue.push(task);pthread_mutex_unlock(&mutex);}//取出一个任务Task<T> TakeTask(){Task<T> task;pthread_mutex_lock(&mutex);if (queue.size() > 0){task = queue.front();queue.pop();}pthread_mutex_unlock(&mutex);return task;}//获取当前队列中的任务个数inline int GetTaskNum(){return queue.size();}
private:pthread_mutex_t mutex; //互斥锁std::queue<Task<T>> queue;
};//线程池
template<typename T>
class ThreadPool
{
public:ThreadPool(int min , int max){//实例化任务队列taskqueue = new TaskQueue<T>;//初始化线程池min_num = min;max_num = max;busy_num = 0;live_num = min;//根据线程最大上限,给线程数组分配内存threadID = new pthread_t[max];if (threadID == nullptr){cout << "new threadID fail" << endl;}//初始化线程IDmemset(threadID, 0, sizeof(pthread_t) * max);//初始化互斥锁和条件变量if (pthread_mutex_init(&mutex_pool, NULL) != 0 ||pthread_cond_init(¬empty, NULL) != 0){cout << "mutex or cond init fail" << endl;}//创建线程for (size_t i = 0; i < min; ++i){pthread_create(&threadID[i], NULL, Work, this);cout << "create thread ID :" << to_string(threadID[i]) << endl;}pthread_create(&managerID, NULL, Manage, this);}~ThreadPool(){shutdown = true;//销毁管理者进程pthread_join(managerID, NULL);//唤醒消费者for (int i = 0; i < live_num; ++i){pthread_cond_signal(¬empty);}if (taskqueue){delete taskqueue;}if (threadID){delete[] threadID;}pthread_mutex_destroy(&mutex_pool);pthread_cond_destroy(¬empty);}//添加任务void Add_Task(Task<T> task){if (shutdown)return;//添加任务,不需加锁,队列中有taskqueue->AddTask(task);//唤醒消费者pthread_cond_signal(¬empty);}//获取忙线程个数int Get_Busy_Num(){int busynum = 0;pthread_mutex_lock(&mutex_pool);busynum = busy_num;pthread_mutex_unlock(&mutex_pool);return busynum;}//获取存活线程个数int Get_Live_Num(){int livenum = 0;pthread_mutex_lock(&mutex_pool); livenum = live_num; pthread_mutex_unlock(&mutex_pool); return livenum; }private://工作的线程任务函数static void* Work(void* args){ThreadPool* pool = static_cast<ThreadPool*>(args);while (true){//访问任务队列加锁pthread_mutex_lock(&pool->mutex_pool);//判断任务队列是否为空,空了就堵塞while (pool->taskqueue->GetTaskNum() == 0 && !pool->shutdown){cout << "thread :" << to_string(pthread_self()) << " waiting..." << endl;pthread_cond_wait(&pool->notempty, &pool->mutex_pool);//解除后 判断是否要销毁进程if (pool->exit_num > 0){pool->exit_num--;if (pool->live_num > pool->min_num){pool->live_num--;pthread_mutex_unlock(&pool->mutex_pool);pool->Thread_Exit();}}}//判断线程池是否要关闭了if (pool->shutdown){pthread_mutex_unlock(&pool->mutex_pool);pool->Thread_Exit();}//从任务队列取出任务Task<T> task = pool->taskqueue->TakeTask();pool->busy_num++;pthread_mutex_unlock(&pool->mutex_pool);cout << "thread :" << to_string(pthread_self()) << " start working..." << endl;task.function(task.args);delete task.args;task.args = nullptr;//任务结束cout << "thread :" << to_string(pthread_self()) << " end working..." << endl;pthread_mutex_lock(&pool->mutex_pool);pool->busy_num--;pthread_mutex_unlock(&pool->mutex_pool);}return nullptr;}//管理者线程任务函数static void* Manage(void* args){ThreadPool* pool = static_cast<ThreadPool*>(args);while (!pool->shutdown){//5秒检测一次sleep(5);pthread_mutex_lock(&pool->mutex_pool);int livenum = pool->live_num;int busynum = pool->busy_num;int queuesize = pool->taskqueue->GetTaskNum();pthread_mutex_unlock(&pool->mutex_pool);const int NUMBER = 2;//创建if (queuesize > livenum && livenum < pool->max_num){pthread_mutex_lock(&pool->mutex_pool);int num = 0;for (int i = 0; i < pool->max_num && num < NUMBER && pool->live_num < pool->max_num ; ++i){if (pool->threadID[i] == 0){pthread_create(&pool->threadID[i], NULL, Work, pool);num++;pool->live_num++;}}pthread_mutex_unlock(&pool->mutex_pool);}//销毁if (busynum * 2 < livenum && livenum > pool->min_num){pthread_mutex_lock(&pool->mutex_pool);pool->exit_num = NUMBER;pthread_mutex_unlock(&pool->mutex_pool);for (int i = 0; i < NUMBER; ++i){pthread_cond_signal(&pool->notempty);}}}return nullptr;}void Thread_Exit(){pthread_t tid = pthread_self();for (int i = 0; i < max_num; ++i){if (threadID[i] == tid){cout << "thread :" << to_string(pthread_self()) << "exiting" << endl;threadID[i] = 0;break;}}pthread_exit(NULL);}
private:pthread_mutex_t mutex_pool;pthread_cond_t notempty;pthread_t* threadID;pthread_t managerID;TaskQueue<T>* taskqueue;int min_num;int max_num;int busy_num;int live_num;int exit_num;bool shutdown = false;};
2. 测试部分
#include"ThreadPool.h"void Task_Test(void* args)
{int num = *(int*)args;cout<<"thread :" << pthread_self() << " is working " << "number =" << num <<endl;sleep(1);return;
}int main()
{//创建线程池ThreadPool<int> pool(3, 10);for (int i = 0; i < 100; ++i){int* num = new int(i+100);pool.Add_Task(Task<int>(Task_Test,num));}sleep(40);return 0;
}
以上只是基于C修改出对应于C++的代码
并且以上代码存在一个问题
输出的结果有时会因为线程原因出现混乱
可以通过加锁来解决,但锁的数量超过1就容易导致死锁问题,所以暂且搁置
二、C++11实现线程池
并非原创,摘于此处
1. 头文件
#pragma once
#include<queue>
#include<thread>
#include<condition_variable>
#include<atomic>
#include<stdexcept>
#include<future>
#include<vector>
#include<functional>namespace std
{#define THREADPOOL_MAX_NUM 16class threadpool{unsigned short _initsize;using Task = function<void()>;vector<thread> _pool;queue<Task> _tasks;mutex _lock;mutex _lockGrow;condition_variable _task_cv;atomic<bool> _run{true};atomic<int> _spa_trd_num{0};public:inline threadpool(unsigned short size = 4){_initsize = size;Add_Thread(size);}inline ~threadpool(){_run = false;_task_cv.notify_all();for (thread& thread : _pool){if (thread.joinable())thread.join();}}template<typename F,typename... Args>auto commit(F&& f, Args&& ...args) -> future<decltype(f(args...)) >{if (!_run)throw runtime_error{"commit auto stop"};using RetType = decltype(f(args...));auto task = make_shared<packaged_task<RetType()>>(bind(forward<F>(f), forward<Args>(args)...));future<RetType> future = task->get_future();{lock_guard<mutex> lock{_lock};_tasks.emplace([task]() {(*task)(); });}if (_spa_trd_num < 1 && _pool.size() < THREADPOOL_MAX_NUM)Add_Thread(1);_task_cv.notify_one();return future;}template<typename F>void commit2(F&& f){if (!_run)return;{lock_guard<mutex> lock{_lock};_tasks.emplace(forward<F>(f));}if (_spa_trd_num < 1 && _pool.size() < THREADPOOL_MAX_NUM)Add_Thread(1);_task_cv.notify_one();}int idlCount() { return _spa_trd_num; }int thrCount() { return _pool.size(); }private:void Add_Thread(unsigned short size){if (!_run)throw runtime_error{"Add_Thread stop"};unique_lock<mutex> lockgrow{_lockGrow};for (; _pool.size() < THREADPOOL_MAX_NUM && size > 0; --size){_pool.emplace_back([this]{while (true){Task task;{unique_lock<mutex> lock{_lock};_task_cv.wait(lock, [this] {return !_run || !_tasks.empty(); });if (!_run && _tasks.empty())return;_spa_trd_num--;task = move(_tasks.front());_tasks.pop();}task();if (_spa_trd_num > 0 && _pool.size() > _initsize)return;{unique_lock<mutex> lock{_lock};_spa_trd_num++;}}});{unique_lock<mutex> lock{_lock};_spa_trd_num++;}} }};
}
要使用pthread依赖库
2. 测试部分
#include"ThreadPool.hpp"
#include<iostream>void fun1(int slp)
{printf("fun1 %ld\n", std::this_thread::get_id());if (slp > 0){printf("fun1 sleep %ld ========= %ld\n", slp, std::this_thread::get_id());std::this_thread::sleep_for(std::chrono::milliseconds(slp));}
}struct gfun
{int operator()(int n){printf("gfun %ld\n", n, std::this_thread::get_id());return 42;}
};class A
{
public:static int Afun(int n = 0) //函数必须是 static 的才能直接使用线程池{std::cout << n << "Afun " << std::this_thread::get_id() << std::endl;return n;}static std::string Bfun(int n, std::string str, char c) {std::cout << n << "Bfun " << str.c_str() << " " << (int)c << " " << std::this_thread::get_id() << std::endl;return str;}
};int main()
try {std::threadpool executor{ 50 };std::future<void> ff = executor.commit(fun1, 0);std::future<int> fg = executor.commit(gfun{}, 0);//std::future<int> gg = executor.commit(A::Afun, 9999); //IDE提示错误,但可以编译运行std::future<std::string> gh = executor.commit(A::Bfun, 9998, "mult args", 123);std::future<std::string> fh = executor.commit([]()->std::string { std::cout << "hello, fh ! " << std::this_thread::get_id() << std::endl; return "hello,fh ret !\n"; });std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << fg.get() << " " << fh.get().c_str() << " " << std::this_thread::get_id() << std::endl;std::cout << " ======= fun1,55 ========= " << std::this_thread::get_id() << std::endl;executor.commit(fun1, 55).get(); //调用.get()获取返回值会等待线程执行完std::threadpool pool(4);std::vector< std::future<int> > results;for (int i = 0; i < 8; ++i){results.emplace_back(pool.commit([i] {std::cout << "hello " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(3));std::cout << "world " << i << std::endl;return i * i;}));}std::this_thread::sleep_for(std::chrono::seconds(15));for (auto&& result : results)std::cout << result.get() << ' ';std::cout << std::endl;return 0;
}
catch (std::exception& e)
{std::cout << "some error " << std::this_thread::get_id() << e.what() << std::endl;
}
- 测试结果
相关文章:

[线程/C++(11)]线程池
文章目录 一、C实现线程池1. 头文件2. 测试部分 二、C11实现线程池1. 头文件2. 测试部分 一、C实现线程池 1. 头文件 #define _CRT_SECURE_NO_WARNINGS #pragma once #include<iostream> #include<string.h> #include<string> #include<pthread.h> #…...

VR防地质灾害安全教育:增强自然灾害知识,提高自我保护意识
VR防地质灾害安全教育系统是一种虚拟仿真技术,可以通过虚拟现实技术模拟地震、泥石流、滑坡等地质灾害的发生和应对过程,帮助人们提高应对突发自然灾害的能力。这种系统的优势在于可以增强自然灾害知识,提高自我保护意识,锻炼人们…...
Mybatis多对多查询案例!
在MyBatis中执行多对多查询需要使用两个主要表和一个连接表(通常称为关联表)来演示。在这个示例中,我们将使用一个示例数据库模型,其中有三个表:students、courses 和 student_courses,它们之间建立了多对多…...

Android OpenCV(七十五): 看看刚”转正“的条形码识别
前言 2021年,我们写过一篇《OpenCV 条码识别 Android 平台实践》,当时的条形码识别模块位于 opencv_contrib 仓库,但是 OpenCV 4.8.0 版本开始, 条形码识别模块已移动到 OpenCV 主仓库,至此我们无需自行编译即可轻松地调用条形码识别能力。 Bar code detector and decoder…...

数据结构——布隆计算器
文章目录 1.什么是布隆过滤器?2.布隆过滤器的原理介绍3.布隆过滤器使用场景4.通过 Java 编程手动实现布隆过滤器5.利用Google开源的 Guava中自带的布隆过滤器6.Redis 中的布隆过滤器6.1介绍6.2使用Docker安装6.3常用命令一览6.4实际使用 1.什么是布隆过滤器…...

金融学复习博迪(第6-9章)
第6章 投资项目分析 学习目的:解释资本预算;资本预算基本法则 资本预算过程包含三个基本要素: 一提出针对投资项目的建议 一对这些建议进行评价 一决定接受和拒绝哪些建议 6.1项目分析的特性 资本预算的过程中的基本单位是单个的投资项目。投…...

解决idea登录github copilot报错问题
试了好多方案都没用,但是这个有用, 打开idea-help-edit custonm vm options 然后在这个文件里面输入 -Dcopilot.agent.disabledtrue再打开 https://github.com/settings/copilot 把这个设置成allow,然后重新尝试登录copilot就行就行 解决方…...

什么是Flex布局?请列举一些Flex布局的常用属性。
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Flex布局(Flexible Box Layout)⭐ Flex布局的常用属性⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之…...
React + TypeScript + antd 常见开发场景
时间戳转格式 // 获取当前时间戳(示例) const timestamp Date.now(); // 或者使用特定的时间戳值// 创建一个新的Date对象,并传入时间戳 const date new Date(timestamp);// 获取年、月、日的值 const year date.getFullYear(); const mon…...

前端基础踩坑记录
前言:在做vue项目时,有时代码没有报错,但运行时却各种问题,没有报错排查起来就很费劲,本人感悟:写前端,需要好的眼神!!!谨以此博客记录下自己的踩坑点。 一、…...
k8s删除pod镜像没响应marking for deletion pod TaintManagerEviction
使用命令强制删除 Pod的状态为"Marking for deletion"表示该Pod正在被标记为待删除状态,但实际上并没有被删除。这可能是因为以下原因之一: 删除操作被阻塞:可能是由于某些资源或容器正在使用该Pod,导致删除操作被阻塞…...
Nginx 使用 lua-nginx-module 来获取post请求中的request和response信息
如果想要在nginx中打印出 http request 的所有 header,需要在编译nginx时开启 1、安装编译所需的依赖 apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev2、创建下载路径 mkdir -p /opt/download3、下载所需的文件 # 不要下载…...
【Opencv】三维重建之cv::recoverPose()函数(1)
官网链接 从估计的本质矩阵和两幅图像中的对应点恢复相机之间的旋转和平移,使用光束法则进行检验。返回通过检验的内点数目。 #include <opencv2/calib3d.hpp>int cv::recoverPose ( InputArray E, InputArray points1, InputArray points2, InputArray …...

Perl兼容正则表达式函数-PHP8知识详解
在php8中有两类正则表达式函数,一类是perl兼容正则表达式函数,另一类是posix扩展正则表达式函数。二者区别不大,我们推荐使用Perl兼容正则表达式函数。 1、使用正则表达式对字符串进行匹配 用正则表达式对目标字符串进行匹配是正则表达式的主…...
Python处理空值NaN
fork_address_tempread_excel_column_to_list(./eqp_info.xls,Sheet1,车辆地址)for i in fork_address_temp:print(type(i))fork_address[0 if address nan else address for address in fork_address_temp]fork_address结果 <class float><class float><class…...
软件机器人助力交通运输局数据录入,实现高效管理
随着科技的迅速发展,许多传统的行业正在寻求通过科技创新优化工作流程、提升效率。在这样的大背景下,交通运输部门也开始注重引入科技手段改善工作流程。博为小帮软件机器人正逐步改变着交通运输局的工作方式。 软件机器人:交通管理的利器 博…...

时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化
时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SGMD分解算法(辛几何模态分解),分解结果可视…...

FinalShell报错:Swap file “.docker-compose.yml.swp“ already exists
FinalShell中编辑docker-compose.yml文件,保存时报错:Swap file ".docker-compose.yml.swp" already exists;报错信息截图如下: 问题原因:有人正在编辑docker-compose.yml文件或者上次编辑没有保存ÿ…...

卷积过程详细讲解
1:单通道卷积 以单通道卷积为例,输入为(1,5,5),分别表示1个通道,宽为5,高为5。假设卷积核大小为3x3,padding0,stride1。 卷积过程如下: 相应的卷积核不断…...
代码随想录第五十六天
代码随想录第五十六天 Leetcode 583. 两个字符串的删除操作Leetcode 72. 编辑距离 Leetcode 583. 两个字符串的删除操作 题目链接: 两个字符串的删除操作 自己的思路:想到了,但是初始化初始错了!!!! 思路1:直接动规五…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...