my_thread_pool
环境
-
windows11
-
C++17
-
vs2022
思路
任务调度
-
FIFO(先进先出)和LIFO(先进后出)。
-
以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:
};
- 以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; //互斥锁
};
-
task_fifo实现用队列queue
-
task_lifo实现用栈stack
-
以ioc容器来注册这两个接口类,方便线程池调用。
-
这个任务调度只用一把锁,需要改变或读取线程池内的私有量就上锁,完事后解锁。
-
未来实现
未来将利用插件模式,这样可以不局限于这两个接口,可以实现诸如随机取任务的类task_random.
线程池
- 指定任务调度方式,利用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;
}
- 指定工作线程数目,生成对应数量的工作线程
//创建工作线程
for (int i = 0; i < thread_num; i++)
{
std::thread *Thread = new std::thread(worker,this);
threadIDs[Thread->get_id()] = Thread;
}
- 工作线程用hash表存放
std::unordered_map<std::thread::id, std::thread*> threadIDs;//存放工作线程
- 工作线程从任务容器中获取一个任务执行,任务执行完成后再取一个任务出来执行。没有任务就等待任务,除非收到结束指令。
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;
-
一个管理者线程
-
管理者线程每隔一秒判断是否需要关停线程池
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();
}
- 整个线程池只用一把锁,需要改变或读取线程池内的私有量就上锁,完事后解锁。
代码文件
测试
- 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;
}
- 结果