「Linux学习」高并发服务器框架 线程池介绍+线程池封装

「Linux学习」高并发服务器框架 线程池介绍+线程池封装

目录

前言

本文主要学习 Linux内核编程 ,结合 Visual Studio 2019 进行跨平台编程,内容包括线程池介绍以及线程池封装

一、线程池介绍

线程池基本概念

  • 线程池 是预先创建线程的一种技术 (服务器真正意义上实现高并发就必须用线程池)
  • 举个例子:生活中的水池,是装东西的容器,用来装水的,线程池当然就是拿来装线程的
  • 线程池在任务还没有到来之前,创建一定数量的线程,放入空闲队列中,这些线程都是处于阻塞状态,不消耗CPU,但占用较小的内存空间
  • 当新任务到来时,缓冲池选择一个空闲线程,把任务传入此线程中运行,如果缓冲池已经没有空闲线程,则新建若干个线程,当系统比较空闲时,大部分线程都一直处于暂停状态,线程池自动销毁一部分线程,回收系统资源

线程池组成部分

  • 线程池类

维护工作者线程队列(包括空闲与忙碌队列)

维护一个任务队列

维护一个线程池调度器指针

  • 线程池调度器 (本身也是一个线程)

负责线程调度

负责任务分配

  • 工作者线程类 (线程池中的线程类的封装)
  • 任务队列
  • 任务接口 (实际的业务逻辑都继承自该接口)

线程池工作原理

根据服务器的需要,来设置线程的数量,可能是10条、20条、30条,根据服务器的承载,10条不代表只能做10个任务,总有任务做的快,有的做的慢,可能可以完成20个任务

举个例子:如上动图所示,当我们服务器收到一个注册业务,是一个服务器要执行的任务,它会进入到任务队列,队列先进先出,顺次执行,任务会唤醒空闲列表当中的一个空闲的线程,接到任务之后,空闲线程会从空闲列表中消失,进入到忙碌列表,去完成对应的任务,完成任务后,从忙碌列表中出去,到空闲列表继续等待新任务

如果,所有的线程都在忙,都在做任务,这时候登录进来,先进入任务队列,会创建一个新的线程来接这个任务,当所有线程都完成任务,回到空闲列表后,新创建的线程销毁,留下原先设置的对应数量线程(类似,保留老员工,把实习生裁员)

  • 队列: 先进先出
  • 空闲列表(链表): 不定长(有的时候可能需要创建新线程来接任务)
  • 忙碌列表(链表): 不定长(有的时候可能需要创建新线程来接任务)

话不多说,咱们上号,封装一下线程池相关函数,来进行测试

二、线程池代码封装

main.cpp

  • 主函数,设置10条线程,来执行30个任务

#include #include #include “ThreadPool.h”#include “ChildTask.h”using namespace std;int main(){ThreadPool* pool = new ThreadPool(10);//10条线程for (int i = 0; i pushTask(task);}while (1) {}return 0;}

ThreadPool.h

  • 对线程池进行设计,核心包括 最大、最小线程数 , 忙碌列表 , 空闲列表 , 任务队列 , 互斥量 , 条件变量 ,以及 线程执行函数

#pragma once#include //队列#include //链表头文件#include //线程头文件#include //find查找#include #include “BaseTask.h”using namespace std;#define MIN_NUM 10//最小值 默认参数class ThreadPool{public:ThreadPool(const int num = MIN_NUM);~ThreadPool();//判断任务队列是否为空bool QueueIsEmpty();//线程互斥量加锁解锁void Lock();void Unlock();//线程条件变量等待和唤醒void Wait();void WakeUp();//添加任务到任务队列void pushTask(BaseTask* task);//从任务队列移除任务BaseTask* popTask(BaseTask* task);//从忙碌回到空闲 工作结束void MoveToIdle(pthread_t id);//从空闲到忙碌 工作开始void MoveToBusy(pthread_t id);//线程执行函数static void* RunTime(void* vo);private:int threadMinNum;//最大线程数量int threadMaxNum;//最小线程数量queuetaskQueue;//任务队列listbusyList;//线程忙碌列表listidleList;//线程空闲列表pthread_mutex_t mutex;//互斥量:做锁pthread_cond_t cond;//条件变量:让线程等待或者唤醒};

ThreadPool.cpp

  • 对函数进行参数的设置,核心在于线程执行函数上的设置,在工作前和工作完设置打印,方便我们进行观察

#include “ThreadPool.h”ThreadPool::ThreadPool(const int num){this->threadMinNum = num;//条件变量、互斥量初始化pthread_mutex_init(&this->mutex, NULL);pthread_cond_init(&this->cond, NULL);pthread_t id;//线程num条创建for (int i = 0; i threadMinNum; i++){//线程创建pthread_create(&id, NULL, RunTime, this);this->idleList.push_back(id);//线程存入空闲列表}}ThreadPool::~ThreadPool(){}//任务队列是否为空bool ThreadPool::QueueIsEmpty(){return this->taskQueue.empty();}//线程加锁void ThreadPool::Lock(){pthread_mutex_lock(&this->mutex);}//线程解锁void ThreadPool::Unlock(){pthread_mutex_unlock(&this->mutex);}//线程等待void ThreadPool::Wait(){pthread_cond_wait(&this->cond, &this->mutex);}//线程唤醒void ThreadPool::WakeUp(){pthread_cond_signal(&this->cond);}//添加任务到任务队列void ThreadPool::pushTask(BaseTask* task){Lock();taskQueue.push(task);Unlock();WakeUp();}//从任务队列移除任务BaseTask* ThreadPool::popTask(BaseTask* task){task = this->taskQueue.front();//从队列头取this->taskQueue.pop();//删除队列头return task;}//从忙碌回到空闲 工作结束void ThreadPool::MoveToIdle(pthread_t id){list::iterator iter;iter = find(busyList.begin(), busyList.end(), id);if (iter != busyList.end()){//从忙碌移除this->busyList.erase(iter);//添加到空闲this->idleList.push_back(*iter);//this->idleList.push_back(id)}}//从空闲到忙碌 工作开始void ThreadPool::MoveToBusy(pthread_t id){list::iterator iter;iter = find(idleList.begin(), idleList.end(), id);if (iter != idleList.end()){//从空闲移除this->idleList.erase(iter);//添加到忙碌this->busyList.push_back(*iter);//this->idleList.push_back(id)}}//线程执行函数void* ThreadPool::RunTime(void* vo){//拿到执行线程自己的id 因为后面要处理忙碌和空闲的情况pthread_t id = pthread_self();//确保主线程与子线程分离,子线程结束后,资源自动回收pthread_detach(id);//线程参数获取ThreadPool* argThis = (ThreadPool*)vo;while (true){argThis->Lock();//如果任务队列为空 线程则一直等待 //知道任务队列不为空则会被pushTask函数唤醒线程while (argThis->QueueIsEmpty()){argThis->Wait();}argThis->MoveToBusy(id);cout << "工作前 任务数:" <taskQueue.size() << endl;cout << "工作前 busy:" <busyList.size() << endl;cout << "工作前 idle:" <idleList.size() << endl;cout << "———————————————–" Unlock();//任务工作task->working();//工作结束argThis->Lock();argThis->MoveToIdle(id);argThis->Unlock();cout << "工作完 任务数:" <taskQueue.size() << endl;cout << "工作完 busy:" <busyList.size() << endl;cout << "工作完 idle:" <idleList.size() << endl;cout >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>” << endl;}return nullptr;}

ChildTask.h

  • 子类配置

#pragma once#include “BaseTask.h”#include #include //sleep头文件using namespace std;class ChildTask :public BaseTask{public:ChildTask(char* data);~ChildTask();void working();};

ChildTask.cpp

  • 子类设置延时模拟做任务的时间比较长

#include “ChildTask.h”ChildTask::ChildTask(char* data) :BaseTask(data)//参数传给父类{}ChildTask::~ChildTask(){}void ChildTask::working(){cout <data << "正在执行……" << endl;sleep(3);//延时3秒 (模拟做业务的时间比较长)}

BaseTask.h

  • 基类设置结构体来装业务

#pragma once#include class BaseTask{public:BaseTask(char* data);~BaseTask();char data[1024]; //装业务virtual void working() = 0;//虚函数};

BaseTask.cpp

  • 基类配置

#include “BaseTask.h”BaseTask::BaseTask(char* data){bzero(this->data, sizeof(this->data));//清空memcpy(this->data, data, sizeof(data));}BaseTask::~BaseTask(){delete this->data;//清除释放}

三、测试效果

  • 通过Linux连接VS进行跨平台编程,我们可以清晰的看到有几个线程是在做任务,几个线程是空闲的,整个过程就很清晰直观的展现出来了,如下动图所示:
  • 10条线程做30个任务的全部记录,如下如所示:

四、总结

创建线程池的好处

  • 线程池的使用,能让我们搭建的高并发服务器真正意义上做到高并发
  • 降低资源消耗

通过重复利用自己创建的线程降低线程创建和销毁造成的消耗

  • 提高响应速度

当任务到达时,任务可以不需要等待线程创建和销毁就能立即执行

  • 提高线程的可管理性

线程式稀缺资源,如果无限的创建线程,不仅会消耗资源,还会降低系统的稳定性

使用线程池可以进行统一分配,调优和监控

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
用户投稿
上一篇 2022年8月16日 09:35
下一篇 2022年8月16日 09:35

相关推荐

  • 短视频策划内容的3个要点(短视频策划内容怎么做)

    短视频在制作时,内容框架非常重要。如果直奔主题,然后结束,聚卓告诉你,这样的短视频已经过时了。现在的短视频需要框架的,但不是任何框架,它需要一种易于理解和消化的框架。而且,现在大多…

    2022年11月27日
  • 存储过程语法(sql server存储过程语法)

    今天小编给各位分享存储过程语法的知识,其中也会对sql server存储过程语法进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! oracle存储过程基本语法…

    2022年11月26日
  • 妻子发微信:“我老公不在,快来”,同事:“下了班就来找你”

    在现如今网络如此发达的时代,大家可以从各个地方了解到全国大事小事,正所谓世界之大无奇不有,每天都发生着奇奇怪怪的事情,今天小编突然看到这样一件事,看完之后都不知道说什么好了。 王某…

    2022年11月26日
  • 《乐队的海边》第二场live秀开启 赵梦为郑秀妍写中文歌词

    今日(11月25日),芒果TV女性经营励志奋斗真人秀《乐队的海边》第二期即将上线。张俪、赵梦、郑秀妍、于文文、刘恋、张天爱在海南省琼海市经营的“炸厨”音乐餐厅蒸蒸日上,收获顾客满满…

    2022年11月25日
  • 自由的工作

    02我国把自由职业者分为三类第一类是小本生意人,如个体零售店小餐馆印刷店装修公司老板,还有路边小摊经营者第二类是没有底薪的推销员,如买保险的人地产经纪房子中介直销人士,卖卡的人。 …

    2022年11月25日
  • cpu性能天梯图2022 AMD CPU天梯图最新排行榜出炉

    用户在DIY自己的主机时选择CPU是非常关键的,CPU可以说是电脑的大脑,大家也都想追求好一点的CPU来使用,但型号太多了,大部分的用户都不知道目前哪一款CPU比较好用,快来看看详…

    2022年11月24日
  • 本人由于个人原因辞职30字(最简单的个人辞职原因)

    做人留一线,日后好相见!我们不断地被职场潜规则着,同时也在制造一些潜规则,每一个离职理由的背后都有一段难以言说的辛酸!离职的时候如果不想说明真实原因,究竟该怎么说合适呢?1、 想读…

    2022年11月24日
  • 忻府区疫情预计什么时候解封(忻府区疫情防控指挥部)

    忻州忻府区本轮疫情发生至今,高风险区一直新增不断,也让大家非常担心当地的疫情。最新通告,针对忻府区当前疫情防控形势,忻府区新冠肺炎疫情防控工作应急处置指挥部决定,11月22日在全区…

    2022年11月22日
  • 11月20日八师石河子市发现2例无症状感染者

    11月20日0—24时,新疆生产建设兵团第八师石河子市在对外地货车司机核酸检测时,发现2例核酸检测初筛异常人员。其中,1例为外地进入师市货车司机“落地核酸检测”发现,1例为石河子高…

    2022年11月21日
  • 二十条发布后,各地防控政策都有哪些新调整?看这里→

    11月11日,国务院联防联控机制综合组发布《关于进一步优化新冠肺炎疫情防控措施 科学精准做好防控工作的通知》,公布进一步优化防控工作的“二十条措施”。“二十条措施”发布后,北京市、…

    2022年11月21日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息