Linux服务器搭建 线程池 函数封装

本文详细介绍了线程池的工作原理,包括任务基类、任务派生类和线程池类的设计。通过C++代码展示了如何封装线程池,包括任务队列、线程互斥量和条件变量的使用。线程池在任务执行过程中能有效地管理和调度线程,提高系统资源利用率。最后,给出了主入口测试代码,模拟了线程池执行多个任务的过程。
摘要由CSDN通过智能技术生成

目录

一:线程池工作原理

二:线程池封装设计

三:模拟线程池执行过程


一:线程池工作原理

【图文解析】线程池工作原理

二:线程池封装设计

任务基类

#pragma once
#include<iostream>
#include<string.h>

using namespace std;
class CBaseTask
{
public:
	CBaseTask(char *data);
	virtual ~CBaseTask();
	char data[1024];
	virtual void working() = 0;
};

#include "CBaseTask.h"

CBaseTask::CBaseTask(char* data)
{
	bzero(this->data,sizeof(this->data));
	memcpy(this->data, data, sizeof(this->data));
}

CBaseTask::~CBaseTask()
{
	delete this->data;
}

任务派生类

派生类继承基类

#pragma once
#include<iostream>
#include<unistd.h>
#include "CBaseTask.h"

using namespace std;
class ChildTask :
    public CBaseTask
{
public:
    ChildTask(char* data);
    ~ChildTask();
    void working();

};

#include "ChildTask.h"

ChildTask::ChildTask(char* data):CBaseTask(data)
{

}

ChildTask::~ChildTask()
{
}

void ChildTask::working()
{
	cout << this->data << "正在执行....." << endl;
    //子任务延时处理模拟真实情境下 子任务在执行时所需耗时
	sleep(3);
}

线程池类设计 

注意点

VS默认不支持线程,需要在链接器中添加命令-pthread

线程条件变量:让线程出现阻塞或者唤醒 

#pragma once
#include<iostream>
#include<queue>
#include<list>
#include<pthread.h>
#include<algorithm>
#include"CBaseTask.h"

#define MIN_NUM 10

using namespace std;

class CThreadPool
{
public:
	CThreadPool(const int num = MIN_NUM);
	~CThreadPool();
	//判断任务队列是否为空
	bool QueueIsEmpty();
	//互斥量操作
	void Lock();
	void unLock();
	//条件变量操作
	void Wait();
	void Wakeup();

    //静态的使用:构造还没执行,还没有类空间,没有类空间,可以有静态函数,静态独立于类存在
    //静态在编译的时候空间就已经生成了
	static void* RunTime(void* pv);//(线程的执行函数设置静态函数)

	void pushTask(CBaseTask* task);//添加任务到任务队列
	CBaseTask* popTask();//从任务队列移除任务
	void MoveIdle(pthread_t id);//移动到空闲链表
	void MoveBusy(pthread_t id);//移动到忙碌链表
private:
	int threadMINNUM;//最小线程数量
	int threadMAXNUM;//最大线程数量
	queue<CBaseTask*>taskQueue;//任务队列
	list<pthread_t>busyList;//忙碌链表
	list<pthread_t>idleList;//空闲链表

	pthread_mutex_t mutex;//线程互斥量 作用:做锁
	pthread_cond_t cond;//线程条件变量 作用:让线程出现阻塞或唤醒

};

#include "CThreadPool.h"

CThreadPool::CThreadPool(const int num)
{
    this->threadMINNUM = num;
    //互斥量初始化
    pthread_mutex_init(&this->mutex,NULL);
    //条件变量初始化
    pthread_cond_init(&this->cond, NULL);
    for (int i = 0; i < this->threadMINNUM; i++)
    {
        pthread_t id;
        //静态 传参  第四个参数可设置this指针
        pthread_create(&id, NULL, RunTime, this);
        this->idleList.push_back(id);
    }
}

CThreadPool::~CThreadPool()
{
}

//判断任务队列是否为空
bool CThreadPool::QueueIsEmpty()
{
    return this->taskQueue.empty();
}

//互斥量加锁
void CThreadPool::Lock()
{
    pthread_mutex_lock(&this->mutex);
}

//互斥量解锁
void CThreadPool::unLock()
{
    pthread_mutex_unlock(&this->mutex);
}

//条件变量等待(阻塞)
void CThreadPool::Wait()
{
    pthread_cond_wait(&this->cond, &this->mutex);
}

//条件变量唤醒 解除线程阻塞状态 让线程开始执行
void CThreadPool::Wakeup()
{
    pthread_cond_signal(&this->cond);
}

//添加任务到任务队列
void CThreadPool::pushTask(CBaseTask* task)
{
    Lock();
    this->taskQueue.push(task);
    unLock();
    //任务添加成功 唤醒线程开始执行工作
    Wakeup();
}

//从任务列表里取出任务
CBaseTask* CThreadPool::popTask()
{
    //任务列表中取出任务
    CBaseTask*  ptask = this->taskQueue.front();
    //任务列表中删除任务
    this->taskQueue.pop();
    //传出任务指针
    return ptask;
}

//线程变空闲 从忙碌到空闲
void CThreadPool::MoveIdle(pthread_t id)
{
    list<pthread_t>::iterator iter;
    iter = find(this->busyList.begin(), this->busyList.end(), id);
    if (iter != this->busyList.end())
    {
        //从忙碌删除
        this->busyList.erase(iter);
        //添加到空闲
        this->idleList.push_back(*iter);

    }
}

//线程变忙碌 从空闲到忙碌
void CThreadPool::MoveBusy(pthread_t id)
{
    list<pthread_t>::iterator iter;
    iter = find(this->idleList.begin(), this->idleList.end(),id);
    if (iter != this->idleList.end())
    {
        //从空闲删除
        this->idleList.erase(iter);
        //添加到忙碌
        this->busyList.push_back(*iter);

    }
}

void* CThreadPool::RunTime(void* pv)
{
    //某线程在执行过程中 先要获取到自己的id 以便之后操作 移动到空闲 移动到忙碌的动作
    pthread_t id = pthread_self();
    //确保主线程与当前的执行线程逻辑完全分离 当前的执行线程执行结束后 id会自动释放
    //分离目的:为了声明这个线程不会阻塞主线程的逻辑  pthread_detach函数不会终止当前的执行线程
    pthread_detach(id);
    CThreadPool * argThis = (CThreadPool*)pv;

    while (true)
    {
        argThis->Lock();
        while (argThis->QueueIsEmpty())
        {
            argThis->Wait();
        }
        
        cout << "工作执行前 任务数: " << argThis->taskQueue.size() << endl;
        cout << "工作执行前 busy: " << argThis->busyList.size() << endl;
        cout << "工作执行前 idle: " << argThis->idleList.size() << endl;

        cout << "---------------------------------------------------------"<< endl;

        argThis->MoveBusy(id);
        //取出任务
        CBaseTask* task = argThis->popTask();
        argThis->unLock();
        //任务工作
        task->working();

        argThis->Lock();
        argThis->MoveIdle(id);
        argThis->unLock();

        cout << "工作执行后 任务数: " << argThis->taskQueue.size() << endl;
        cout << "工作执行后 busy: " << argThis->busyList.size() << endl;
        cout << "工作执行后 idle: " << argThis->idleList.size() << endl;

        cout << "---------------------------------------------------------" << endl;

    }
    return nullptr;
}

主入口测试 

#include<iostream>
#include"CThreadPool.h"
#include"ChildTask.h"
using namespace std;

int main()
{
	CThreadPool* pool = new CThreadPool(10);
	for (int i = 0; i < 10; i++)
	{
		char buf[40] = { 0 };
		sprintf(buf , " %s%d ", "任务", i);
        //父类指针指向子类的空间,多态
		CBaseTask* task = new ChildTask(buf);
		pool->pushTask(task);
	}
	while (1){}
	return 0;
}

三:模拟线程池执行过程

下图可以看出

设置任务业务10个,一开始空闲线程10 忙碌线程0

后面随着任务一个接一个地执行下去

忙碌线程+1递增 空闲线程-1递减

由下图可见

当所有的任务都执行完成了以后,忙碌线程会一个一个地转换为空闲线程

直到所有的忙碌线程都转化为空闲线程 

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenruhan_QAQ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值