本文主要学习Linux内核编程,结合Visual Studio 2019进行跨平台编程,内容包括线程池介绍以及线程池封装
- 线程池在任务还没有到来之前,创建一定数量的线程,放入空闲队列中,这些线程都是处于阻塞状态,不消耗CPU,但占用较小的内存空间
- 当新任务到来时,缓冲池选择一个空闲线程,把任务传入此线程中运行,如果缓冲池已经没有空闲线程,则新建若干个线程,当系统比较空闲时,大部分线程都一直处于暂停状态,线程池自动销毁一部分线程,回收系统资源
- 线程池类
维护工作者线程队列(包括空闲与忙碌队列)
维护一个任务队列
维护一个线程池调度器指针
- 线程池调度器(本身也是一个线程)
负责线程调度
负责任务分配
- 工作者线程类(线程池中的线程类的封装)
- 任务队列
- 任务接口(实际的业务逻辑都继承自该接口)
根据服务器的需要,来设置线程的数量,可能是10条、20条、30条,根据服务器的承载,10条不代表只能做10个任务,总有任务做的快,有的做的慢,可能可以完成20个任务
🌰举个例子:如上动图所示,当我们服务器收到一个注册业务,是一个服务器要执行的任务,它会进入到任务队列,队列先进先出,顺次执行,任务会唤醒空闲列表当中的一个空闲的线程,接到任务之后,空闲线程会从空闲列表中消失,进入到忙碌列表,去完成对应的任务,完成任务后,从忙碌列表中出去,到空闲列表继续等待新任务
如果,所有的线程都在忙,都在做任务,这时候登录进来,先进入任务队列,会创建一个新的线程来接这个任务,当所有线程都完成任务,回到空闲列表后,新创建的线程销毁,留下原先设置的对应数量线程(类似,保留老员工,把实习生裁员)
- 队列:先进先出
- 空闲列表(链表):不定长(有的时候可能需要创建新线程来接任务)
- 忙碌列表(链表):不定长(有的时候可能需要创建新线程来接任务)
- #include <iostream>
- #include "ThreadPool.h"
- #include "ChildTask.h"
- using namespace std;
-
- int main()
- {
- ThreadPool* pool = new ThreadPool(10);//10条线程
-
- for (int i = 0; i < 30; i++)//30个任务
- {
- char buf[40] = { 0 };//初始化
- sprintf(buf, "%s%d","任务", i);
-
- BaseTask* task = new ChildTask(buf);
- pool->pushTask(task);
- }
-
- //方便测试,设置死循环,让线程不退出
- while (1)
- {
- }
- return 0;
- }
- #pragma once
- #include <queue>//队列
- #include <list>//链表头文件
- #include <pthread.h>//线程头文件
- #include "BaseTask.h"
- #include <algorithm>//find的包
- #include <iostream>
- 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;//最小线程数量
- queue<BaseTask*>taskQueue;//任务队列
- list<pthread_t>busyList;//忙碌列表
- list<pthread_t>idleList;//空闲列表
- pthread_cond_t cond;//条件变量,目的:让线程等待或者唤醒
- pthread_mutex_t mutex;//互斥量,目的:做锁
- };
-
- #include "ThreadPool.h"
-
- ThreadPool::ThreadPool(const int num)
- {
- this->threadMaxNum = num;
-
- //条件变量、互斥量初始化
- pthread_mutex_init(&this->mutex, NULL);//初始化
- pthread_cond_init(&this->cond, NULL);//初始化
-
- pthread_t id;
-
- //线程num条创建
- for (int i = 0; i < this->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<pthread_t>::iterator iter;
- //查找忙碌队列中的线程
- iter = find(busyList.begin(), busyList.end(), id);//find查找
- if (iter != busyList.end())
- {
- //从忙碌到移除
- this->busyList.erase(iter);
- //添加到空闲
- this->idleList.push_back(*iter);//*iter
- }
- }
- //从空闲到忙碌(状态:工作开始)
- void ThreadPool::MoveToBusy(pthread_t id)
- {
- list<pthread_t>::iterator iter;
- //查找空闲队列中的线程
- iter = find(idleList.begin(), idleList.end(), id);//find查找
- if (iter != idleList.end())
- {
- //从空闲移除
- this->idleList.erase(iter);
- //添加到忙碌
- this->busyList.push_back(*iter);//*iter
- }
- }
- //线程执行函数
- 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 << "工作前 任务数:" << argThis->taskQueue.size() << endl;
- cout << "工作前 busy:" << argThis->busyList.size() << endl;
- cout << "工作前 idle:" << argThis->idleList.size() << endl;
- cout << "-----------------------------------------" << endl;
-
- //取任务
- BaseTask* task;
- task = argThis->popTask(task);
-
- argThis->Unlock();
-
- //任务工作
- task->working();
-
- //工作结束
- argThis->Lock();
- argThis->MoveToIdle(id);
- argThis->Unlock();
-
- cout << "工作完 任务数:" << argThis->taskQueue.size() << endl;
- cout << "工作完 busy:" << argThis->busyList.size() << endl;
- cout << "工作完 idle:" << argThis->idleList.size() << endl;
- cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl;
- }
-
- return nullptr;
- }
- #pragma once
- #include "BaseTask.h"
- #include <iostream>
- #include <unistd.h> //sleep头文件
-
- using namespace std;
-
- class ChildTask :
- public BaseTask
- {
- public:
- ChildTask(char* data);
- ~ChildTask();
- void working();
- };
-
- #include "ChildTask.h"
-
- ChildTask::ChildTask(char* data):BaseTask(data)//参数传给父类
- {
- }
-
- ChildTask::~ChildTask()
- {
- }
-
- void ChildTask::working()
- {
- cout <<"正在执行ing"<< this->data << endl;//打印
- sleep(3);//延时3秒 (模拟做业务的时间比较长)
- }
- #pragma once
- #include <string.h>
-
- class BaseTask
- {
- public:
- BaseTask(char * data);
- ~BaseTask();
- char data[1024]; //装业务
- virtual void working() = 0;//虚函数
- };
-
- #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进行跨平台编程,我们可以清晰的看到有几个线程是在做任务,几个线程是空闲的,整个过程就很清晰直观的展现出来了,如下动图所示:
以上就是本文的全部内容啦!如果对您有帮助,麻烦点赞啦!收藏啦!欢迎各位评论区留言!!!