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

【Linux】系统编程简单线程池(C++)

目录

【1】线程池概念

【1.1】线程池

【1.2】线程池的应用场景

【1.3】线程池的种类

【1.4】线程池示例

【2】线程池代码


【1】线程池概念

【1.1】线程池

        一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

【1.2】线程池的应用场景

  • 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

  • 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

  • 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限, 出现错误.

【1.3】线程池的种类

  • 半同步/半异步模式

  • 领导者/跟随着模式

【1.4】线程池示例

  • 创建固定数量线程池,循环从任务队列中获取任务对象,获取到任务对象后,执行任务对象中的任务接口。

【2】线程池代码

【Makefile文件】

# 创建变量关联关系
cc=c++
standard=-std=c++11
linkLib=-l pthread
​
# 创建编译文件依赖关系
myThreadPool:ThreadPool.cc$(cc) -o $@ $^ $(standard) $(linkLib)  
​
# 创建删除命令
.PHONY:clean
clean:rm -f myThreadPool

【Task.hpp文件】

#pragma once
#include <iostream>
#include <string>
#include <functional>
​
/* 计算任务 */
class CalTask
{
public:using func_t = std::function<int(int, int, char)>;
​
public:/* 构造函数 */CalTask() {}
​/* 构造函数 */CalTask(int x, int y, char op, func_t func): _x(x), _y(y), _op(op), _callBalk(func){}
​
public:/* 仿函数 */std::string operator()(){int result = _callBalk(_x, _y, _op);
​char buffer[64];snprintf(buffer, sizeof(buffer), "%d %c %d = %d", _x, _op, _y, result);return buffer;}
​
public:/* 返回打印公式 */std::string ToTaskString(){char buffer[64];snprintf(buffer, sizeof(buffer), "%d %c %d = ?", _x, _op, _y);return buffer;}
​
private:int _x;int _y;char _op;func_t _callBalk;
};
​
/* 执行计算的方法 */
int MyCalculate(int x, int y, char op)
{int result = 0;switch (op){case '+':result = x + y;break;
​case '-':result = x - y;break;
​case '*':result = x * y;break;
​case '/':{if (y == 0){std::cerr << "div zero error!" << std::endl;result = -1;}else{result = x / y;}break;}
​case '%':{if (y == 0){std::cerr << "mod zero error!" << std::endl;result = -1;}else{result = x % y;}break;}
​default:break;}
​return result;
}
​
/* 保存任务 */
class SaveTask
{
public:using func_t = std::function<void(const std::string &)>;
​
public:/* 构造函数 */SaveTask() {}/* 构造函数 */SaveTask(const std::string &message, func_t func): _message(message), _callBalk(func){}
​
public:/* 仿函数 */void operator()(){_callBalk(_message);}
​
private:std::string _message;func_t _callBalk;
};
​
/* 保存方法 */
void Save(const std::string& massage){std::string target = "./log.txt";FILE *fp = fopen(target.c_str(), "a+");if(fp == NULL){std::cerr << "fopen fail!" << std::endl;return;}
​fputs(massage.c_str(), fp);fputs("\n", fp);fclose(fp);
}

【Thread.hpp文件】

#pragma once
#include <iostream>
#include <functional>
#include <cstdio>
#include <cassert>
​
namespace ThreadNs
{/* 线程连接上下文 */class Thread;class ConnectText{public:/* 构造函数 */ConnectText() : _this(nullptr), _args(nullptr) {}/* 析构函数 */~ConnectText() {}
​public:Thread *_this;void *_args;};
​
​/* 线程类封装 */class Thread{public:using func_t = std::function<void *(void *)>; // // 从定义类似函数指针类型:返回值是:void*  参数是:void*
​public:/* 构造函数 */Thread(const int number = 0){// 创建线程的名称char buffer[64];snprintf(buffer, sizeof(buffer), "Thread-%d", number);_tName = buffer;}
​/* 析构函数 */~Thread() {}public:/* 线程启动 */void Start(const func_t& func, void *args = nullptr){// 建立关系_func = func;_args = args;
​// 创建线程后,启动ConnectText *cnt = new ConnectText();cnt->_this = this;cnt->_args = _args;
​int n = pthread_create(&_tid, nullptr, StartRoutine, (void *)cnt);assert(n == 0); (void)n;       // 编译debug的方式时assert是存在的,release方式assert是不存在的,到时n就是定义了,但是没有被使用的变量。// 在有的编译器下会有warning。}
​/* 线程等待 */void Join(){int n = pthread_join(_tid, nullptr);assert(n == 0);(void)n;}
​public:/* 获取线程名字 */std::string GetThreadName(){return _tName;}
​private:/* 线程函数 */static void *StartRoutine(void *args){ // 在类内创建线程,想让线程执行对应的方法,需要将方法设置称为staticConnectText *cnt = static_cast<ConnectText *>(args);void *exRet = cnt->_this->RoutineRun(cnt->_args);delete cnt;return exRet;}
​void *RoutineRun(void *args){return _func(args);}
​private:pthread_t _tid;     // 线程idstd::string _tName; // 线程名称func_t _func;       // 线程函数void *_args;        // 线程参数};
}

【ThreadPool.hpp文件】

#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include "Thread.hpp"
#include "LockGuard.hpp"
​
/* 引用命名空间 */
using namespace ThreadNs;
​
/* 线程上下文数据 */
template <class T>
class ThreadPool;
​
template <class T>
class ThreadData
{
public:ThreadData(ThreadPool<T> *tp, const std::string &n): _threadPool(tp), _name(n){}
​
public:ThreadPool<T> *_threadPool;std::string _name;
};
​
​
​
/* 线程池封装 */
const int g_num = 5;    // 设置线程数
template <class T>
class ThreadPool
{
public:/* 构造函数 */ThreadPool(const int &num = g_num): _threadNum(num){// 初始化线程锁pthread_mutex_init(&_mutex, nullptr);// 初始化线程条件变量pthread_cond_init(&_cond, nullptr);
​// 将每个线程地址Push到线程地址容器中for (int i = 0; i < _threadNum; i++){_threads.push_back(new Thread(i + 1));}}
​/* 析构函数 */~ThreadPool(){// 释放线程锁pthread_mutex_destroy(&_mutex);// 释放线程条件变量pthread_cond_destroy(&_cond);
​// 遍历释放for (auto &t : _threads){delete t;}}
​
public:/* 开启线程池 */void Run(){// 启动线程for (const auto &t : _threads){ThreadData<T> *td = new ThreadData<T>(this, t->GetThreadName());t->Start(HandlerTask, td);std::cout << t->GetThreadName() << ": Start..." << std::endl;}
​// // 阻塞式等待回收线程// for (const auto &t : _threads)// {//     t->Join();//     std::cout << t->GetThreadName() << ": Recycle..." << std::endl;// }}
​
public:/* 获取锁 */pthread_mutex_t *Mutex() { return &_mutex; }/* 线程加锁 */void Lock() { pthread_mutex_lock(&_mutex); }/* 线程解锁 */void UnLock() { pthread_mutex_unlock(&_mutex); }/* 线程等待 */void ThreadWait() { pthread_cond_wait(&_cond, &_mutex); }/* 判断是否有任务 */bool IsEmpty() { return _taskQueue.empty(); }
​/* 新增任务 */void Push(const T &in){// 加锁->自动解锁LockGuard LockGuard(&_mutex);// 新增任务_taskQueue.push(in);// 环形线程执行pthread_cond_signal(&_cond);}
​/* 执行任务 */T Pop(){// 创建T对象T t;// 获取栈顶任务t = _taskQueue.front();_taskQueue.pop();// 返回任务return t;}
​
private:/* 线程池共享线程 */static void *HandlerTask(void *args){ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
​while (true){// 创建任务对象T t;
​{// 加锁->自动解锁LockGuard LockGuard(td->_threadPool->Mutex());// 如果没有任务,等待任务if (td->_threadPool->IsEmpty()){td->_threadPool->ThreadWait();}t = td->_threadPool->Pop();// 解锁td->_threadPool->UnLock();}
​// 打印信息std::cout << td->_name << ":承接一个任务[" << t.ToTaskString() << "],任务的执行结果是[" << t() << "]" << std::endl;}return nullptr;}
​
private:int _threadNum;                 // 线程数量std::vector<Thread *> _threads; // 存放线程地址的容器std::queue<T> _taskQueue;       // 存放线程任务的队列pthread_mutex_t _mutex;         // 线程锁pthread_cond_t _cond;           // 线程条件变量
};

【ThreadPool.cc文件】

#include <iostream>
#include <memory>
#include <unistd.h>
#include "Task.hpp"
#include "ThreadPool.hpp"
using namespace std;
​
int main() 
{// 智能指针管理unique_ptr<ThreadPool<CalTask>> tP(new ThreadPool<CalTask>());// 启动线程池tP->Run();
​// 手动派发任务int x;int y;char op;while (1){std::cout << "请输入数据1# ";std::cin >> x;std::cout << "请输入数据2# ";std::cin >> y;std::cout << "请输入要进行的运算# ";std::cin >> op;CalTask t(x, y, op, MyCalculate);tP->Push(t);sleep(1);}return 0;
}

【代码测试结果】

相关文章:

【Linux】系统编程简单线程池(C++)

目录 【1】线程池概念 【1.1】线程池 【1.2】线程池的应用场景 【1.3】线程池的种类 【1.4】线程池示例 【2】线程池代码 【1】线程池概念 【1.1】线程池 一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&a…...

数据结构之道:如何选择适合你的数据存储

文章目录 第1节&#xff1a;数据结构的基本原理1.1 时间复杂度和空间复杂度1.2 数据的访问方式1.3 数据的增删操作 第2节&#xff1a;常见的数据结构2.1 数组&#xff08;Array&#xff09;2.2 链表&#xff08;Linked List&#xff09;2.3 栈&#xff08;Stack&#xff09;2.4…...

MySQL定时删除XX天数据

写在前面 定时删除数据方式有多种方法&#xff0c;在实际工作中很多人可能会通过编码实现&#xff0c;也有人可能会通过脚本定时执行SQL进行定时删除对应数据。 今天使用MySQL自带的删除策略。 MYSQL删除策略 从MySQL5.1.6起&#xff0c;增加了一个非常有特色的功能–事件调…...

vue在js文件中调用$notify

我们在vue组件中可以直接 this.$notify({title: 修改成功,type: success,duration: 2500 })但在js中 我们this的指向就会发生一些不同 但是 其实 学过构造函数和原型链的人会很好理解这一点 每一个vue组件都是通过 vue构造出来的一个实例 所以 他们的this都是指向当前实例对象…...

C++从入门到精通

目录 C 语言特性C 学习大纲初级阶段1. 基础概念2. 数据类型和变量3. 运算符和表达式4. 控制流程 中级阶段5. 函数和模块化编程6. 数据结构7. 面向对象编程&#xff08;OOP&#xff09; 高级阶段8. 文件操作和流9. 模板和泛型编程10. 多线程和并发编程11. 高级主题 实际项目 C 语…...

2023网络安全面试题(附答案)+面经

前言 随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;相应的想要进入到网络安全行业的人也越来越多&#xff0c;为了拿到心仪的Offer之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 所以在这里我归纳总结了一些网…...

数据结构_红黑树

1、二叉树 每一个分支不能超过两个 2、 排序数/查找树 在二叉树的基础上&#xff0c;元素是有大小顺序的左 子树 小&#xff0c;右 子树 大 3、平衡树 左孩子数 和 右孩子数 相等 4、不平衡树 5、 红黑树 特点&#xff1a;趋近于平衡树&#xff0c;查询的速度非常的快&#xf…...

一百八十八、Hive——HiveSQL查询表中的日期是星期几(亲测,附截图)

一、目的 指标需要查询以工作日和周末维度的数据统计&#xff0c;因此需要根据数据的日期判断这一天属于星期几&#xff0c;周一到周五为工作日&#xff0c;周六到周日为周末 二、SQL查询 &#xff08;一&#xff09;SQL语句 selectday,case when pmod(datediff(create_tim…...

基础题——数组

输入一个电子邮箱&#xff0c;检查用户输入的字符串是否为有效的电子邮件地址 正确的邮箱地址&#xff1a; 必须包含字符&#xff0c;不能是开头或结尾 必须以 .com结尾 和.com之间必须有其他字符 public static void main(String[] args) {Scanner sc new Scanner(System.in…...

Qt地铁智慧换乘系统浅学( 一 )存储站点,线路信息

存储 定义所需要的容器定义最大最小经纬度[统计站点信息 在经纬度网站](https://map.jiqrxx.com/jingweidu/)读取统计的信息存储到容器其他的一些相关函数debug 显示存储的信息更新最小最大经纬度的函数获取两点之间的距离 根据经纬度 定义所需要的容器 extern QMap<QStrin…...

Python之xToolkit库

文章目录 一、xToolkit是什么&#xff1f;二、准备工作1.引入库2.导入数据 三、使用时间模块-xdatetime判断时间格式是否正确get方法获取时间戳获取年月日时分秒时间推移计算时间替换时间扩展两个时间的差值开始与结束时间时间是否在指定区间中 字符串模块-xstring字符串格式校…...

2w+深度梳理!全网最全NLP面试题总结!

目录 技术交流群 1、命名实体识别常见面试篇2、关系抽取常见面试篇3、事件抽取 常见面试篇4、NLP 预训练算法常见面试篇5、Bert 常见面试篇6、文本分类 常见面试篇7、文本匹配 常见面试篇8、问答系统常见面试篇FAQ 检索式问答系统常见面试篇问答系统工具篇常见面试篇 9、对话系…...

Spring 学习(五)JavaConfig 实现配置

1. 使用 JavaConfig 实现配置 JavaConfig 是 Spring 项目的一个子项目&#xff0c;Spring 4 后成为核心功能。 注意&#xff1a; 如果开启包扫描&#xff0c;加载配置类以后就可以通过反射拿到配置类中的对象了。Bean 只写在方法上&#xff0c;返回的是一个对象&#xff0c;但…...

【Synapse数据集】Synapse数据集介绍和预处理,数据集下载网盘链接

【Segment Anything Model】做分割的专栏链接&#xff0c;欢迎来学习。 【博主微信】cvxiaoyixiao 本专栏为公开数据集的介绍和预处理&#xff0c;持续更新中。 文章目录 1️⃣Synapse数据集介绍文件结构源文件样图文件内容 2️⃣Synapse数据集百度网盘下载链接官网下载登录下…...

【运动规划算法项目实战】Dynamic Window Approach算法(附ROS C++代码)

文章目录 前言一、简介1.1 DWA算法原理1.2 DWA算法的应用场景1.4 DWA算法的优缺点1.4.1 优点1.4.2 缺点二、代码实现2.1 算法细节2.1.1 DWA的控制输入:2.1.2 动态窗口的计算2.1.3 评价函数的优化2.2 程序说明2.21 PathGenerator2.2.2 WaypointAction2.2.3 使用方法2.3 代码演示…...

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 试题 A: 子 2023

[蓝桥杯 2023 国 B] 子 2023 试题 A: 子 2023 【问题描述】 小蓝在黑板上连续写下从 1 1 1 到 2023 2023 2023 之间所有的整数&#xff0c;得到了一个数字序列&#xff1a; S 12345678910111213 ⋯ 20222023 S 12345678910111213\cdots 20222023 S12345678910111213⋯2…...

Unity 场景淡入淡出效果

一. 使用Dotween&#xff0c;建议使用我的方式 FindObjectOfType<SceneFadeInAndOut>().FadeIn(() > { Debug.Log("Fade in MenuStart Scene"); }); using DG.Tweening; using System; using System.Numerics; using UnityEngi…...

快速使用Spring Cache

哈喽~大家好&#xff0c;这篇我们来看看快速使用Spring Cache。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【日常学习上的分享】 &#x1f949;与这篇相关的文章&#xff1a; R…...

Scrum敏捷开发培训内训:提升团队能力和效率的重要途径

在当今软件开发领域&#xff0c;Scrum敏捷开发方法越来越受到重视。Scrum是一种以团队协作为基础&#xff0c;注重灵活性和快速响应变化的方法。 为了帮助团队更好地掌握Scrum敏捷开发&#xff0c;培训变得越来越重要。Scrum敏捷开发方法注重高效协作、快速迭代和持续改进。通…...

kaggle新赛:Optiver 美股价格预测赛题解析

赛题名称&#xff1a;Optiver - Trading at the Close 赛题链接&#xff1a;https://www.kaggle.com/competitions/optiver-trading-at-the-close 赛题背景 证券交易所是快节奏、高风险的环境&#xff0c;每一秒都很重要。随着交易日接近尾声&#xff0c;强度不断升级&#…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...