Linux/C++——线程池

什么是线程池

线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。
在这里插入图片描述

为什么要引入线程池

  1. 单线程的场景中,如在服务端的服务中,要对多个客户端进行服务,单个线程会阻塞住,使效率大大降低,这时候就要多个线程,
  2. 然而在使用多个线程的时候,来一个任务,就要创建一个线程去服务,当客户端退出又需要销毁线程,而频繁的创建线程销毁线程效率很低,另一方面,
  3. 如果一次有很多个线程,计算机当中的线程越多,CPU的压力就越大,因为CPU要不断在这些线程之间来回切换,此时CPU在调度线程的时候,线程和线程之间切换的成本就会变得很高。此外,一旦线程太多,每一个线程再次被调度的周期就变长了,而线程是为客户端提供服务的,线程被调度的周期变长,客户端也迟迟得不到应答。
  • 所以这里可以引入线程池,用固定数量的线程来处理任务,而这些任务由一个任务队列来管理,当有新的任务到来的时候,就可以将任务Push到线程池当中,如果线程池当中没有任务那么当前线程就会进入休眠状态。

线程池的应用场景

  1. 12306网上购票系统等
  2. 云盘文件上传和下载
  3. 网购

线程池的代码实现

  • 线程池中的多个线程负责从任务队列当中拿任务,并将拿到的任务进行处理。
  • 线程池对外提供一个pushtask接口,用于让外部线程能够将任务push到任务队列当中。
  • 任务类中能够在接收任务后对任务进行处理
  • 任务队列可能会被多个线程同时访问,所以在对任务队列操作引入互斥锁

任务类的实现

#pragma once
#include <iostream>
#include <string>
#include <unistd.h>class Task
{
public:Task(){}Task(int x, int y, char op) : _x(x), _y(y), _op(op), _result(0), _exitCode(0){}std::string formatArg(){return std::to_string(_x) + _op + std::to_string(_y) + "= ";}std::string formatRes(){return std::to_string(_result) + "(" + std::to_string(_exitCode) + ")";}void run(){switch (_op){case '+':_result = _x + _y;break;case '-':_result = _x - _y;break;case '*':_result = _x * _y;break;case '/':{if (_y == 0)_exitCode = -1;else_result = _x / _y;}break;case '%':{if (_y == 0)_exitCode = -2;else_result = _x % _y;}break;default:break;}usleep(100000);std::cout<<formatArg()<<formatRes()<<std::endl;}~Task(){}private:int _x;int _y;char _op;int _result;int _exitCode;
};

线程池的实现

#pragma once#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Task.hpp"const static int N = 5;template <class T>
class ThreadPool
{
public:ThreadPool(int num = N) : _num(num), _threads(num){pthread_mutex_init(&_lock, nullptr);pthread_cond_init(&_cond, nullptr);}void lockQueue(){pthread_mutex_lock(&_lock);}void unlockQueue(){pthread_mutex_unlock(&_lock);}void threadWait(){pthread_cond_wait(&_cond, &_lock);}void threadWakeup(){pthread_cond_signal(&_cond);}bool isEmpty(){return _tasks.empty();}T popTask(){T t = _tasks.front();_tasks.pop();return t;}static void *threadRoutine(void *args){pthread_detach(pthread_self());ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);while (true){// 1. 检测有没有任务// 2. 有:处理// 3. 无:等待// 细节:必定加锁tp->lockQueue();while (tp->isEmpty()){tp->threadWait();}T t = tp->popTask(); // 从公共区域拿到私有区域tp->unlockQueue();t.run(); // 处理任务,应不应该在临界区中处理?1,0}}void init(){// TODO}void start(){for (int i = 0; i < _num; i++){pthread_create(&_threads[i], nullptr, threadRoutine, this); // ?}}void pushTask(const T &t){lockQueue();_tasks.push(t);threadWakeup();unlockQueue();}~ThreadPool(){pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_cond);}private:std::vector<pthread_t> _threads;int _num;std::queue<T> _tasks; // 使用stl的自动扩容的特性pthread_mutex_t _lock;pthread_cond_t _cond;
};

测试代码

#include"ThreadPool.hpp"
#include<memory>
int main(){std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>());tp->init();tp->start();const char* op = "+-*/%";for( ;;){sleep(1);int x = rand() % 100;int y = rand() % 100;int index = rand() % 5;Task task(x, y, op[index]);tp->pushTask(task);}
}

在这里插入图片描述

拓展操作

  1. 封装一个线程类
  2. 封装一个互斥锁类,在构造的时候加锁,析构的时候解锁
  3. 用单例模式来操作线程池

拓展后的代码

线程类
#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <pthread.h>class Thread
{
public:typedef enum{NEW = 0,RUNNING,EXITED} ThreadStatus;typedef void (*func_t)(void *);public:Thread(int num, func_t func, void *args) : _tid(0), _status(NEW), _func(func), _args(args){char name[128];snprintf(name, sizeof(name), "thread-%d", num);_name = name;}int status() { return _status; }std::string threadname() { return _name; }pthread_t threadid(){if (_status == RUNNING)return _tid;else{return 0;}}// 是不是类的成员函数,而类的成员函数,具有默认参数this,需要static// 但是会有新的问题:static成员函数,无法直接访问类属性和其他成员函数static void *runHelper(void *args){Thread *ts = (Thread*)args; // 就拿到了当前对象// _func(_args);(*ts)();return nullptr;}void operator ()() //仿函数{if(_func != nullptr) _func(_args);}void run(){int n = pthread_create(&_tid, nullptr, runHelper, this);if(n != 0) exit(1);_status = RUNNING;}void join(){int n = pthread_join(_tid, nullptr);if( n != 0){std::cerr << "main thread join thread " << _name << " error" << std::endl;return;}_status = EXITED;}~Thread(){}private:pthread_t _tid;std::string _name;func_t _func; // 线程未来要执行的回调void *_args;ThreadStatus _status;
};
互斥锁类
#pragma once#include <iostream>
#include <pthread.h>class Mutex // 自己不维护锁,有外部传入
{
public:Mutex(pthread_mutex_t *mutex):_pmutex(mutex){}void lock(){pthread_mutex_lock(_pmutex);}void unlock(){pthread_mutex_unlock(_pmutex);}~Mutex(){}
private:pthread_mutex_t *_pmutex;
};class LockGuard // 自己不维护锁,有外部传入
{
public:LockGuard(pthread_mutex_t *mutex):_mutex(mutex){_mutex.lock();}~LockGuard(){_mutex.unlock();}
private:Mutex _mutex;
};
任务类
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>class Task
{
public:Task(){}Task(int x, int y, char op) : _x(x), _y(y), _op(op), _result(0), _exitCode(0){}void operator()(){switch (_op){case '+':_result = _x + _y;break;case '-':_result = _x - _y;break;case '*':_result = _x * _y;break;case '/':{if (_y == 0)_exitCode = -1;else_result = _x / _y;}break;case '%':{if (_y == 0)_exitCode = -2;else_result = _x % _y;}break;default:break;}usleep(100000);}std::string formatArg(){return std::to_string(_x) + _op + std::to_string(_y) + "= ?";}std::string formatRes(){return std::to_string(_result) + "(" + std::to_string(_exitCode) + ")";}~Task(){}private:int _x;int _y;char _op;int _result;int _exitCode;
};
线程池类
#pragma once#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include "Thread.hpp"
#include "Task.hpp"
#include "lockGuard.hpp"const static int N = 5;template <class T>
class ThreadPool
{
private:ThreadPool(int num = N) : _num(num){pthread_mutex_init(&_lock, nullptr);pthread_cond_init(&_cond, nullptr);}ThreadPool(const ThreadPool<T> &tp) = delete;void operator=(const ThreadPool<T> &tp) = delete;public:static ThreadPool<T> *getinstance(){if(nullptr == instance) // 为什么要这样?提高效率,减少加锁的次数!{LockGuard lockguard(&instance_lock);if (nullptr == instance){instance = new ThreadPool<T>();instance->init();instance->start();}}return instance;}pthread_mutex_t *getlock(){return &_lock;}void threadWait(){pthread_cond_wait(&_cond, &_lock);}void threadWakeup(){pthread_cond_signal(&_cond);}bool isEmpty(){return _tasks.empty();}T popTask(){T t = _tasks.front();_tasks.pop();return t;}static void threadRoutine(void *args){// pthread_detach(pthread_self());ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);while (true){// 1. 检测有没有任务// 2. 有:处理// 3. 无:等待// 细节:必定加锁T t;{LockGuard lockguard(tp->getlock());while (tp->isEmpty()){tp->threadWait();}t = tp->popTask(); // 从公共区域拿到私有区域}// for testt();std::cout << "thread handler done, result: " << t.formatRes() << std::endl;// t.run(); // 处理任务,应不应该在临界区中处理?1,0}}void init(){for (int i = 0; i < _num; i++){_threads.push_back(Thread(i, threadRoutine, this));}}void start(){for (auto &t : _threads){t.run();}}void check(){for (auto &t : _threads){std::cout << t.threadname() << " running..." << std::endl;}}void pushTask(const T &t){LockGuard lockgrard(&_lock);_tasks.push(t);threadWakeup();}~ThreadPool(){for (auto &t : _threads){t.join();}pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_cond);}private:std::vector<Thread> _threads;int _num;std::queue<T> _tasks; // 使用stl的自动扩容的特性pthread_mutex_t _lock;pthread_cond_t _cond;static ThreadPool<T> *instance;static pthread_mutex_t instance_lock;
};template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;template <class T>
pthread_mutex_t ThreadPool<T>::instance_lock = PTHREAD_MUTEX_INITIALIZER;
测试代码
#include "ThreadPoolEnd.hpp"
#include "Task.hpp"
#include <memory>int main()
{printf("0X%x\n", ThreadPool<Task>::getinstance());//打印单例的地址printf("0X%x\n", ThreadPool<Task>::getinstance());printf("0X%x\n", ThreadPool<Task>::getinstance());printf("0X%x\n", ThreadPool<Task>::getinstance());printf("0X%x\n", ThreadPool<Task>::getinstance());printf("0X%x\n", ThreadPool<Task>::getinstance());const char* op = "+-*/%";while (true){sleep(1);int x = rand() % 100;int y = rand() % 100;int index = rand() % 5;Task t(x, y, op[index]);ThreadPool<Task>::getinstance()->pushTask(t); //单例对象也有可能在多线程场景中使用!}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3019113.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

不得不聊的微服务Gateway

一、 什么是Gateway&#xff1f; 1.网关的由来 单体应用拆分成多个服务后&#xff0c;对外需要一个统一入口&#xff0c;解耦客户端与内部服务 2.网关的作用 Spring Cloud Gateway是Spring Cloud生态系统中的一员&#xff0c;它被设计用于处理所有微服务的入口流量。作为一…

志邦家居流程项目中心负责人郑瑶瑶受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 志邦家居股份有限公司流程项目中心负责人、战略及变革委员会秘书长郑瑶瑶女士受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“PMO在制造企业的标准化建设之路”。大会将于6月29-30日在北京举办&#xff0c;敬请关注&…

社区智能奶柜:创业新机遇

社区智能奶柜&#xff1a;创业新机遇 在追求高质量生活的今天&#xff0c;健康食品成为大众焦点。社区智能奶柜适时登台&#xff0c;革新了居民获取新鲜牛奶的传统模式&#xff0c;为创业者开辟了一片蓝海市场。 一、新兴创业蓝海&#xff1a;牛奶随享站 日常膳食中&#xf…

【系统架构师】-UML-用例图(Use Case)

1、概述 用于表示系统功能需求&#xff0c;以及应用程序与用户或者与其他应用程序之间的交互关系。 2、组成 参与者&#xff08;Actors&#xff09;&#xff1a;与系统交互的用户或其他系统。用一个人形图标表示。用例&#xff08;Use Cases&#xff09;&#xff1a;系统需要…

sql查询数据语句

select * from 表名 where 列名 某个数据名字 查询某个表名中的某列是否有某个数据

孩子咳嗽,积食?可以试试宋乐冬医生分享的几个缓解方法~

最近气温变化大忽冷忽热&#xff0c;多变的天气容易引发儿童疾病。 不少妈妈也在后台咨询&#xff0c;想要学习一下常用的小儿推拿&#xff0c;在孩子身体出现轻微不适时&#xff0c;能够给孩子做做小儿推拿来辅助治疗&#xff0c;缓解不适恢复健康。 今天我们就一起学习一下&a…

视频剪辑图文实例:一键操作,轻松实现视频批量片头片尾减时

视频剪辑是现代媒体制作中不可或缺的一环&#xff0c;而批量处理视频更是许多专业人士和爱好者的常见需求。在剪辑过程中&#xff0c;调整视频的片头片尾时长可以显著提升视频的质量和观感。本文将通过图文实例的方式&#xff0c;向您展示如何一键操作&#xff0c;轻松实现视频…

Debian——安装syzkaller——2024

系统:Debian 远程连接——我是不想安装tools没有办法复制黏贴,所以远程,根据个人情况选择是否远程连接 就是说使用Windows自带的远程mstsc,使用的不是ssh22端口,是TCP 3389端口 mkdir debian cd debian 二:安装go编译器 打开终端。使用wget命令从官方网站或可信的镜像…

关于行内(块)元素vertical-align:middle;居中对齐

有时候 会发现 对行内元素或者行内块元素设置垂直居中vertical-align&#xff1a;middle&#xff1b;与不设置&#xff0c;没有什么变化 这是因为vertical-align不是作用于行内&#xff08;块&#xff09;元素自身&#xff0c;它是作用于其他行内&#xff08;块&#xff09;元素…

醛固酮(Aldosterone)/Aldosterone ELISA kit--比色竞争法酶免疫检测试剂盒

醛固酮&#xff08;Aldosterone&#xff09;是一种由肾上腺皮质中的胆固醇合成的类固醇激素。醛固酮在肾脏和肝脏中代谢&#xff0c;并作为控制钠钾平衡的关键盐皮质激素发挥作用。肾上腺合成和释放醛固酮主要受肾素-血管紧张素-醛固酮系统&#xff08;RAAS&#xff09;的调节&…

图纸管理的高效策略与最佳实践

图纸管理的高效策略与最佳实践 在工程设计、产品研发和建筑行业中&#xff0c;图纸管理是一项至关重要的任务。随着项目规模的扩大和复杂性的增加&#xff0c;如何高效、有序地管理图纸已成为企业和团队关注的焦点。本文将为您介绍图纸管理的高效策略与最佳实践&#xff0c;帮助…

检测机构的双资质是什么?

CMA和CNAS是两种在检测、校准和认证领域具有权威性的资质。 CMA资质全称为“检验检测机构资质认定”&#xff08;China Inspection Body and Laboratory Mandatory Approval&#xff09;。它是根据《中华人民共和国计量法》等相关法规&#xff0c;由国家认证认可监督管理委员会…

面试中算法(2的整数次幂)

判断一个正整数是否是2的整数次幂&#xff08;如16是2的4次方&#xff0c;返回true;18不是2的整数次幂&#xff0c;则返回false&#xff09;&#xff0c;要求性能尽可能高。 使用一个整型变量&#xff0c;让它从1开始不断乘以2&#xff0c;将每一次乘2的结果和 目标整数进行比较…

印尼本土电商平台Tokopedia和Akulaku如何高效上货?你需要EasyBoss ERP产品批量编辑功能

作为印尼本土电商平台&#xff0c;Tokopedia及Akulaku在印尼拥有相当大的用户群体&#xff0c;根据Similarweb数据显示&#xff0c;这两个电商平台分别占据谷歌及苹果应用下载榜的第三四名。对于有意布局印尼本土电商市场的中国卖家&#xff0c;Tokopedia或Akulaku都不失为一个…

50kw 直流充电桩测试仪的基础知识

直流充电桩测试仪是专门用于检测和测试直流充电桩性能的设备。它能够对充电桩的输出电压、电流、功率、效率等关键参数进行精确测量&#xff0c;以确保充电桩的正常运行和充电安全。 一、工作原理 直流充电桩测试仪主要通过模拟实际充电过程&#xff0c;对充电桩的各项性能进行…

共享WiFi项目加盟骗局:共享WiFi贴码收益真的月入过万?

如今每个人的手机都是智能手机&#xff0c;我们几乎随时随地都需要网络的陪伴。而随着共享经济的概念深入人心&#xff0c;一种名为“共享WiFi贴码”的新兴事物逐渐走入了我们的视线。据说通过这种方式&#xff0c;人们可以实现轻资产创业&#xff0c;甚至有人声称能借此达到月…

GreatSQL的sp中添加新的sp_instr引入的bug解析

GreatSQL的sp中添加新的sp_instr引入的bug解析 一、问题发现 在一次开发中用到的sp需要添加新的sp_instr以满足需求&#xff0c;但是添加了数个sp_instr以后发现执行新的sp会发生core。 注&#xff1a;本次使用的GreatSQL 8.0.32-25 1、sp_head.cc的init_sp_psi_keys()代码里…

阴影渲染在AI去衣技术中的关键作用

引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;深度学习在图像处理领域取得了突破性的进展。其中&#xff0c;AI去衣技术作为一种高度复杂的图像到图像的转换过程&#xff0c;不仅要求算法能够精确地识别并处理衣物纹理和结构&#xff0c;还要求生成的结果具有高度的…

Java 【数据结构】 TreeSetTreeMap(二叉搜索树详解)【神装】

登神长阶 第八神装 TreeSet 第九神装 TreeMap 目录 &#x1f489; 一.二叉搜索树 &#x1fa78;1. 定义 &#x1f48a;2. 基本操作 &#x1fa79;3. 插入操作 &#x1fa7c;4. 查找操作 &#x1fa7a;5. 删除操作* &#x1fa7b;6. 遍历操作 &#x1fa92;7.性能分析 …

3D应用开发工具HOOPS与云计算:推动工程设计行业的数字化转型

关于云计算 在信息技术迅猛发展的今天&#xff0c;云计算已经成为企业进行数字化转型的重要推手。云计算通过互联网提供包括服务器、存储、数据库、网络、软件、分析和智能等在内的计算服务&#xff0c;这些服务通常以按需供应的方式提供&#xff0c;允许用户根据使用量进行付…