C++实现的线程池

my_thread_pool

环境

  1. windows11

  2. C++17

  3. vs2022

思路

任务调度

  1. FIFO(先进先出)和LIFO(先进后出)。

  2. 以task_control为接口

class Task_Control
{
public:
    //添加任务
    virtual void Add_Task(Task task) = 0;
    //添加任务                   
    virtual void Add_Task(std::string name, callback f, void* arg) = 0;
    //取出任务       
    virtual Task take_Task() = 0;
    //返回任务数量                           
    virtual int return_task_number() = 0;
protected:
    Task_Control();
    ~Task_Control();
private:
};
  1. 以task_fifo和task_lifo继承接口并实现功能
//先进先出
class Task_FIFO :public Task_Control
{
public:
    //添加任务
    void Add_Task(Task task);
    //添加任务                   
    void Add_Task(std::string name, callback f, void* arg);
    //取出任务       
    Task take_Task();
    //返回任务数量                           
    int return_task_number();
protected:

private:
    std::queue<Task> Task_Queue;
    std::mutex m_mutex;    //互斥锁
};

//先进后出
class Task_LIFO :public Task_Control
{
public:
    //添加任务
    void Add_Task(Task task);
    //添加任务                   
    void Add_Task(std::string name, callback f, void* arg);
    //取出任务       
    Task take_Task();
    //返回任务数量                           
    int return_task_number();
protected:

private:
    std::stack<Task> Task_Stack;
    std::mutex m_mutex;    //互斥锁
};
  1. task_fifo实现用队列queue

  2. task_lifo实现用栈stack

  3. 以ioc容器来注册这两个接口类,方便线程池调用。

  4. 这个任务调度只用一把锁,需要改变或读取线程池内的私有量就上锁,完事后解锁。

  5. 未来实现

未来将利用插件模式,这样可以不局限于这两个接口,可以实现诸如随机取任务的类task_random.

线程池

  1. 指定任务调度方式,利用ioc容器,生成所需的任务调度.。
//注册任务调度
	ioc.registerType<Task_Control,Task_FIFO>("fifo");
	ioc.registerType<Task_Control, Task_LIFO>("lifo");

	//获取任务调度
	task_control = ioc.resolve<Task_Control>(control);
	if (task_control == nullptr)
	{
		std::cout << "error:没有:" << control << "类型的任务调度" << std::endl;
	}
  1. 指定工作线程数目,生成对应数量的工作线程
//创建工作线程
		for (int i = 0; i < thread_num; i++)
		{
			std::thread *Thread = new std::thread(worker,this);
			threadIDs[Thread->get_id()] = Thread;
		}
  1. 工作线程用hash表存放
std::unordered_map<std::thread::id, std::thread*> threadIDs;//存放工作线程
  1. 工作线程从任务容器中获取一个任务执行,任务执行完成后再取一个任务出来执行。没有任务就等待任务,除非收到结束指令。
		pool->m_mutex.lock();
		if (pool->shut_down == true)
		{
			pool->m_mutex.unlock();
			return;
		}
		if (pool->task_control->return_task_number() == 0)
		{
			pool->m_mutex.unlock();
			continue;
		}
		Task task = pool->task_control->take_Task();
		pool->busy_num++;
		pool->m_mutex.unlock();
		
		//执行任务
		task.fun(task.arg);

		printf("%s任务执行完成----------------by 工作thread: %d \n",task.name.c_str(),std::this_thread::get_id());

		delete task.arg;
		task.arg = NULL;

  1. 一个管理者线程

  2. 管理者线程每隔一秒判断是否需要关停线程池

while (true)
	{
		//每隔1秒检测一次
		std::this_thread::sleep_for(std::chrono::seconds(1));

		//获取数据
		pool->m_mutex.lock();
		std::string msg = "总线程数:" + std::to_string(pool->thread_num)
			+ " 当前忙碌线程数:" + std::to_string(pool->busy_num);
		std::cout << msg << std::endl;

		if (pool->busy_num == 0 && pool->task_control->return_task_number() == 0)
		{
			//下达关闭所有线程指令
			pool->shut_down = true;
			pool->m_mutex.unlock();
			return;
		}
		pool->m_mutex.unlock();
	}
  1. 整个线程池只用一把锁,需要改变或读取线程池内的私有量就上锁,完事后解锁。

代码文件

gitee地址

测试

  1. main.cpp
#include "Thread_Pool.h"
#include <iostream>
#include <string>
#include <windows.h>
void fun(void *arg)
{
    Sleep(3000);
}

int main()
{
    Thread_Pool tp(4, "lifo");

    for (int i = 0; i < 100; i++)
    {
        tp.addTask(Task(std::to_string(i),fun,nullptr));
    }
    std::cout << "ok\n";
    return 0;
}
  1. 结果

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱睡觉更爱学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值