当前位置: 首页 > news >正文

[线程/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(&notempty, 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(&notempty);}if (taskqueue){delete taskqueue;}if (threadID){delete[] threadID;}pthread_mutex_destroy(&mutex_pool);pthread_cond_destroy(&notempty);}//添加任务void Add_Task(Task<T> task){if (shutdown)return;//添加任务,不需加锁,队列中有taskqueue->AddTask(task);//唤醒消费者pthread_cond_signal(&notempty);}//获取忙线程个数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防地质灾害安全教育系统是一种虚拟仿真技术&#xff0c;可以通过虚拟现实技术模拟地震、泥石流、滑坡等地质灾害的发生和应对过程&#xff0c;帮助人们提高应对突发自然灾害的能力。这种系统的优势在于可以增强自然灾害知识&#xff0c;提高自我保护意识&#xff0c;锻炼人们…...

Mybatis多对多查询案例!

在MyBatis中执行多对多查询需要使用两个主要表和一个连接表&#xff08;通常称为关联表&#xff09;来演示。在这个示例中&#xff0c;我们将使用一个示例数据库模型&#xff0c;其中有三个表&#xff1a;students、courses 和 student_courses&#xff0c;它们之间建立了多对多…...

Android OpenCV(七十五): 看看刚”转正“的条形码识别

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

数据结构——布隆计算器

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

金融学复习博迪(第6-9章)

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

解决idea登录github copilot报错问题

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

什么是Flex布局?请列举一些Flex布局的常用属性。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Flex布局&#xff08;Flexible Box Layout&#xff09;⭐ Flex布局的常用属性⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之…...

React + TypeScript + antd 常见开发场景

时间戳转格式 // 获取当前时间戳&#xff08;示例&#xff09; const timestamp Date.now(); // 或者使用特定的时间戳值// 创建一个新的Date对象&#xff0c;并传入时间戳 const date new Date(timestamp);// 获取年、月、日的值 const year date.getFullYear(); const mon…...

前端基础踩坑记录

前言&#xff1a;在做vue项目时&#xff0c;有时代码没有报错&#xff0c;但运行时却各种问题&#xff0c;没有报错排查起来就很费劲&#xff0c;本人感悟&#xff1a;写前端&#xff0c;需要好的眼神&#xff01;&#xff01;&#xff01;谨以此博客记录下自己的踩坑点。 一、…...

k8s删除pod镜像没响应marking for deletion pod TaintManagerEviction

使用命令强制删除 Pod的状态为"Marking for deletion"表示该Pod正在被标记为待删除状态&#xff0c;但实际上并没有被删除。这可能是因为以下原因之一&#xff1a; 删除操作被阻塞&#xff1a;可能是由于某些资源或容器正在使用该Pod&#xff0c;导致删除操作被阻塞…...

Nginx 使用 lua-nginx-module 来获取post请求中的request和response信息

如果想要在nginx中打印出 http request 的所有 header&#xff0c;需要在编译nginx时开启 1、安装编译所需的依赖 apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev2、创建下载路径 mkdir -p /opt/download3、下载所需的文件 # 不要下载…...

【Opencv】三维重建之cv::recoverPose()函数(1)

官网链接 从估计的本质矩阵和两幅图像中的对应点恢复相机之间的旋转和平移&#xff0c;使用光束法则进行检验。返回通过检验的内点数目。 #include <opencv2/calib3d.hpp>int cv::recoverPose ( InputArray E, InputArray points1, InputArray points2, InputArray …...

Perl兼容正则表达式函数-PHP8知识详解

在php8中有两类正则表达式函数&#xff0c;一类是perl兼容正则表达式函数&#xff0c;另一类是posix扩展正则表达式函数。二者区别不大&#xff0c;我们推荐使用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…...

软件机器人助力交通运输局数据录入,实现高效管理

随着科技的迅速发展&#xff0c;许多传统的行业正在寻求通过科技创新优化工作流程、提升效率。在这样的大背景下&#xff0c;交通运输部门也开始注重引入科技手段改善工作流程。博为小帮软件机器人正逐步改变着交通运输局的工作方式。 软件机器人&#xff1a;交通管理的利器 博…...

时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化

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

FinalShell报错:Swap file “.docker-compose.yml.swp“ already exists

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

卷积过程详细讲解

1&#xff1a;单通道卷积 以单通道卷积为例&#xff0c;输入为&#xff08;1,5,5&#xff09;&#xff0c;分别表示1个通道&#xff0c;宽为5&#xff0c;高为5。假设卷积核大小为3x3&#xff0c;padding0&#xff0c;stride1。 卷积过程如下&#xff1a; 相应的卷积核不断…...

代码随想录第五十六天

代码随想录第五十六天 Leetcode 583. 两个字符串的删除操作Leetcode 72. 编辑距离 Leetcode 583. 两个字符串的删除操作 题目链接: 两个字符串的删除操作 自己的思路:想到了&#xff0c;但是初始化初始错了&#xff01;&#xff01;&#xff01;&#xff01; 思路1:直接动规五…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...