线程池
手写线程池 – C
线程池原理
线程池的组成主要分为3个部分:
任务队列 – 存储需要处理的任务,由工作的线程来处理这些任务
- 通过线程池提供的API函数,将一个待处理的任务添加到任务队列,或从任务队列删除
- 已处理的任务会被任务队列删除
- 线程池的使用者,也就是调用线程池函数 往任务队列中添加任务的线程就是生产者线程
工作的线程(任务队列任务的消费者),N个
- 线程池维护了一定数量的工作线程,他们的作用是不停的读任务队列,从里面取出任务队列并处理
- 工作线程相当于是任务队列的消费者角色
- 如果任务队列为空,工作的线程将会被阻塞(使用条件变量/信号量)
- 如果阻塞后有了新任务,由生产者将阻塞解除,工作线程开始工作
管理者线程(不处理任务队列中的任务),1个
任务 – 周期性对任务队列中的任务数量以及处于忙状态的工作线程个数进行检测:
当任务过多时,适当创建一些新的工作线程
当任务过少时,可以适当销毁一些工作线程
任务队列
// 任务结构体
typedef struct Task {
void (*function)(void* arg);
void* arg;
}Task;
线程池定义
// 线程池结构体
struct Threadpool {
// 任务队列
Task* taskQ;
int queueCapacity; // 容量
int queueSize; // 当前任务个数
int queueFront; // 队头 -- 取数据
int queueRear; // 队尾 -- 放数据
pthread_t managerID; // 管理者线程ID
pthreat_t *threadIDs; // 工作线程ID
int minNum; // 最小线程数量
int maxNum; // 最大线程数量
int busyNum; // 忙的线程个数
int liveNum; // 存活的线程个数
int exitNum; // 要销毁的线程个数
pthread_mutex_t mutexPool; // 整个线程池的锁
pthread_mutex_t mutexBusy; // busyNum变量的锁
pthread_cond_t notFull; // 任务队列是否满了
pthread_cond_t notEmpty; // 任务队列是否空了
int shutdown; // 是否销毁线程池(1-销毁)
};
头文件声明
#ifndef _THEADPOOL_H
#define _THREADPOOL_H
typedef struct ThreadPool ThreadPool;
// 创建线程并初始化
ThreadPool *threadPoolCreate(int min, int max, int queueSize);
// 销毁线程池
int threadPoolDestroy(ThreadPool* pool);
// 给线程池添加任务
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void arg);
// 获取线程池中工作线程的个数
int threadPoolBusyNum(ThreadPool* pool);
// 获取线程池中活着的线程个数
int threadPoolAliveNum(ThreadPool* pool);
/
// 工作线程任务函数
void* worker(void* arg);
// 管理者线程任务函数
void* manager(void* arg);
// 单个线程退出
void threadExit(ThreadPool* pool);
#endif
源文件定义
创建线程并初始化
ThreadPool* threadPoolCreate(int min, int max, int queueSize) {
ThreadPool* pool =
(ThreadPool*)malloc(sizeof(ThreadPool));
do {
if(pool == NULL) {
printf("malloc threadpool fail...\n");
break;
}
pool->threadIDs = (pthread*)malloc(sizeof(pthread) * max);
if(pool->threadIDs == NULL) {
printf("malloc threadIDs fail...\n");
break;
}
memset(pool->threadIDs, 0, sizeof(pthread_t) * max);
// 初始化,里面的线程ID是无符号长整型
pool->minNum = min;
pool->maxNum = max;
pool->busyNum = 0;
pool->liveNum = min;
pool->exitNum = 0;
// 初始化线程锁和条件变量
if(pthread_mutex_init(&pool->mutexPool, NULL) != 0 ||
pthread_mutex_init(&pool->mutexBusy, NULL) != 0 ||
pthread_cond_init(&pool->notEmpty, NULL) != 0) ||
pthread_cond_init(&pool->notFull, NULL) != 0)) {
printf("mutex or condition init fail...\n");
break;
}
// 初始化任务队列
pool->taskQ = (Task*)malloc(sizeof(Task) * queueSize);
pool->queueCapacity = queueSize;
pool->queueSize = 0;
pool->queueFront = 0;
pool->queueRear = 0;
pool->shutdown = 0;
// 创建线程
pthread_create(&pool->managerID, NULL, manager, pool);
for(int i = 0; i < min; ++i) {
pthread_create(&pool->threadIDs[i], NULL, work, pool);
}
return pool;
}