线程池封装 1
实现思路:
-
组件:
- pthread_t *workers; //工作线程数组
- pthread_t manager; //管理者线程
- TaskQueue *task_queue; //任务队列
-
思路:
- 多个工作线程,外部线程添加任务,结合阻塞任务队列实现生产消费者模型;
- 管理者线程负责工作线程的调度策略
- 比如说,存活数小于设定最大线程数且存在未执行任务,则创建线程
- 当忙碌线程小于当前存活线程数且,则进行线程销毁.
实现: 任务和任务队列
#ifndef TASK_HPP
#define TASK_HPP
#include <pthread.h>
#include <queue>
using callback = void(*)(void*);
struct Task
{
Task()
{
function = nullptr;
arg = nullptr;
}
Task(callback f, void *arg)
{
function = f;
this->arg = arg;
}
callback function;
void *arg;
};
class TaskQueue
{
public:
TaskQueue()
{
pthread_mutex_init(&__mutex__, NULL);
}
~TaskQueue()
{
pthread_mutex_destroy(&__mutex__);
}
void add_task(Task &task)
{
pthread_mutex_lock(&__mutex__);
__queue__.push(task);
pthread_mutex_unlock(&__mutex__);
}
void add_task(callback func, void *arg)
{
Task task(func, arg);
add_task(task);
}
Task take_task()
{
Task task;
pthread_mutex_lock(&__mutex__);
if(__queue__.size() > 0)
{
task = __queue__.front();
__queue__.pop();
}
pthread_mutex_unlock(&__mutex__);
return task;
}
inline int get_task_number()
{
return __queue__.size();
}
private:
pthread_mutex_t __mutex__;
std::queue<Task> __queue__;
};
#endif
实现:线程池
#include "task.hpp"
#include "../log/log.h"
#include <pthread.h>
#include <string.h>
#include <iostream>
#include <string>
#include <unistd.h>
class ThreadPool
{
public:
ThreadPool(int min, int max);
~ThreadPool();
void add_task(Task &task); //添加任务
int get_busy_number(); //获取忙碌线程数
int get_alive_number(); //获取存活线程数
private:
static void *worker(void *arg); //工作线程函数
static void *manager(void*arg); //管理者线程调度逻辑
void thread_exit(); //退出指定工作线程
static const int __NUMBER__ = 2;//每次新建线程数上限制
private:
pthread_mutex_t __lock__; //队列访问互斥锁
pthread_cond_t __notEmpty__; //生产消费者模型条件变量
pthread_t *__workers__; //工作线程数组
pthread_t __manager__; //管理者线程
TaskQueue *__task_queue__; //任务队列
int __minNum__; //最小线程数
int __maxNum__; //最大线程数
int __busyNum__; //忙碌线程数
int __aliveNum__; //存活线程数
int __exitNum__; //待退出线程数
bool __shutdown__ = false; //关闭池子标志位置
};
ThreadPool::ThreadPool(int min, int max)
{
__task_queue__ = new TaskQueue;
do
{
__minNum__ = min;
__maxNum__ = max;
__busyNum__ = 0;
__aliveNum__ = 0;
__workers__ = new pthread_t[max];
memset(__workers__, 0, sizeof(pthread_t)*max);
if (pthread_mutex_init(&__lock__, nullptr)!=0||
pthread_cond_init(&__notEmpty__,nullptr)!=0)
{
// printf("THREADPOOL: init mutex or condition fail...");
break;
}
for(int i=0; i<min; ++i)
{
pthread_create(&__workers__[i],nullptr,worker,this);
}
pthread_create(&__manager__, nullptr, manager, this);
} while (0);
}
ThreadPool::~ThreadPool()
{
__shutdown__ = 1;
pthread_join(__manager__, nullptr);
for(int i=0; i<__aliveNum__; ++i)
{
pthread_cond_signal(&__notEmpty__);
}
if(__task_queue__) delete __task_queue__;
if(__workers__) delete __workers__;
pthread_mutex_destroy(&__lock__);
pthread_cond_destroy(&__notEmpty__);
}
void ThreadPool::add_task(Task &task)
{
if (__shutdown__) return;
__task_queue__->add_task(task);
pthread_cond_signal(&__notEmpty__);
}
int ThreadPool::get_busy_number()
{
int tmp = 0;
pthread_mutex_lock(&__lock__);
tmp = __busyNum__;
pthread_mutex_unlock(&__lock__);
return tmp;
}
int ThreadPool::get_alive_number()
{
int tmp = 0;
pthread_mutex_lock(&__lock__);
tmp = __aliveNum__;
pthread_mutex_unlock(&__lock__);
return tmp;
}
void* ThreadPool::worker(void* arg)
{
ThreadPool *pool = static_cast<ThreadPool*>(arg);
while (true)
{
pthread_mutex_lock(&pool->__lock__);
while (pool->__task_queue__->get_task_number()==0 && !pool->__shutdown__)
{
// printf("THREADPOOL: Thread %ld is waiting.", pthread_self());
pthread_cond_wait(&pool->__notEmpty__, &pool->__lock__);
if(pool->__exitNum__>0)
{
pool->__exitNum__--;
if(pool->__aliveNum__ > pool->__minNum__)
{
pool->__aliveNum__--;
pthread_mutex_unlock(&pool->__lock__);
pool->thread_exit();
}
}
}
if(pool->__shutdown__)
{
pthread_mutex_unlock(&pool->__lock__);
pool->thread_exit();
}
Task task = pool->__task_queue__->take_task();
pool->__busyNum__++;
pthread_mutex_unlock(&pool->__lock__);
// printf("THREADPOOL: Thread %ld start working....", pthread_self());
task.function(task.arg);
// delete task.arg;
task.arg = nullptr;
// printf("THREADPOOL: Thread %ld end working...", pthread_self());
pthread_mutex_lock(&pool->__lock__);
pool->__busyNum__--;
pthread_mutex_unlock(&pool->__lock__);
}
}
void* ThreadPool::manager(void*arg)
{
ThreadPool *pool = static_cast<ThreadPool*>(arg);
while (!pool->__shutdown__)
{
sleep(3);
pthread_mutex_lock(&pool->__lock__);
int queueSize = pool->__task_queue__->get_task_number();
int liveNum = pool->__aliveNum__;
int busyNum = pool->__busyNum__;
pthread_mutex_unlock(&pool->__lock__);
if (queueSize > liveNum && liveNum < pool->__maxNum__)
{
pthread_mutex_lock(&pool->__lock__);
int counter = 0;
for(int i=0; i < pool->__maxNum__ && counter < __NUMBER__; ++i)
{
if(pool->__workers__[i] == 0)
{
pthread_create(&pool->__workers__[i], nullptr, worker,pool);
counter++;
pool->__aliveNum__++;
}
}
pthread_mutex_unlock(&pool->__lock__);
}
if(busyNum*2<liveNum && liveNum>pool->__minNum__)
{
pthread_mutex_lock(&pool->__lock__);
pool->__exitNum__ = __NUMBER__;
pthread_mutex_unlock(&pool->__lock__);
for(int i=0; i<__NUMBER__; i++)
{
pthread_cond_signal(&pool->__notEmpty__);
}
}
}
return nullptr;
}
void ThreadPool::thread_exit()
{
pthread_t tid = pthread_self();
for (int i = 0; i < __maxNum__; ++i)
{
if (__workers__[i] == tid)
{
__workers__[i] = 0;
// printf("THREADPOOL: thread %ld is exitiong...", pthread_self());
break;
}
}
pthread_exit(NULL);
}
测试代码
#include "../threadpool/task.hpp"
#include "../threadpool/threadpool.hpp"
#include <stdlib.h>
#include <stdio.h>
void task_func(void *arg)
{
int num = *(int*)arg;
printf("thread %ld is working, num=%d\n",pthread_self(),num);
sleep(1);
}
int main(int argc, char const *argv[])
{
ThreadPool pool(1,5);
for(int i=0; i<100; ++i)
{
int *num = (int*)malloc(sizeof(int));
*num = i+100;
Task task(task_func, num);
pool.add_task(task);
}
sleep(30);
return 0;
}
引用
- https://subingwen.cn/linux/threadpool-cpp/