当前位置: 首页 > 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:直接动规五…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...