线程池思路
任务队列作为一个缓冲区,线程池中的线程抢任务。
threadpool_t结构体
struct threadpool_t {
pthread_mutex_t lock;
pthread_mutex_t thread_counter; //busy_thread_num修改时加解锁
pthread_cond_t queue_not_full;
pthread_cond_t queue_not_empty;
pthread_t *thread; //线程数组
pthread_t adjust_thread; //管理者线程管理线程池的线程数量
task_queue_t *task_queue; //任务队列数组
int min_thread_num;
int max_thread_num;
int live_thread_num;
int busy_thread_num;
int wait_exit_thread_num; //等待销毁的线程数
int queue_front;
int queue_rear;
int queue_size;
int queue_max_size;
int shutdown; //shutdown == 0 线程池开,shutdown == 1线程池关
};
task_queue_t结构体
typedef struct {
void *(*function)(void *); //回调函数
void *arg; //参数
} task_queue_t; //任务
main()函数
threadpool_create()
初始化线程池threadpool_add()
向任务队列添加任务threadpool_destory()
int main() {
struct threadpool_t *threadpool = threadpool_create(3, 100, 100); //min_thread_num, max_thread_num, queue_max_size
intptr_t nums[80];
for (intptr_t i = 0; i < 80; i++) {
nums[i] = i; //task;
threadpool_add(threadpool, process, (void *)nums[i]); // 线程池,回调函数,泛型参数
}
sleep(10);
threadpool_destory(threadpool);
return 0;
}
threadpool_create() 函数初始化threadpool_t
- 为
int
类型的变量赋值 - 初始化锁和条件变量
malloc
出max_thread_num
个thread
- 为
min_thread_num
个线程创建线程pthread_create()
,调用func_thread
函数 - 为管理者线程创建线程,调用
func_adjust_thread
函数 malloc
出queue_max_size
个task_queue_t
threadpool_t *threadpool_create(int min_thread_num, int max_thread_num, int queue_max_size){
struct threadpool_t *pool = (threadpool_t *)malloc(sizeof(threadpool_t));
do{
if (pool == NULL) {
printf("pool malloc failed");
break;
}
// 为int类型的变量赋值
pool->min_thread_num = min_thread_num;
pool->max_thread_num = max_thread_num;
pool->live_thread_num = min_thread_num;
pool->busy_thread_num = 0;
pool->wait_exit_thread_num = 0;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->queue_size = 0;
pool->queue_max_size = queue_max_size;
pool->shutdown = 0;
//初始化锁和条件变量
if (pthread_mutex_init(&(pool->lock), NULL) != 0 ||
pthread_mutex_init(&(pool->thread_counter), NULL) != 0 ||
pthread_cond_init(&(pool->queue_not_full), NULL) != 0 ||
pthread_cond_init(&(pool->queue_not_empty), NULL) != 0 ) {
printf("init the lock or cond failed");
break;
}
//malloc出max_thread_num个thread
pool->thread = (pthread_t *)malloc(sizeof(pthread_t) * max_thread_num);
if (pool->thread == NULL) {
printf("thread malloc failed");
break;
}
//赋0
memset(pool->thread, 0, sizeof(pthread_t) * max_thread_num);
//为min_thread_num个线程创建线程pthread_create(),调用func_thread函数
for (int i = 0; i < min_thread_num; i++) {
pthread_create(&(pool->thread[i]), NULL, func_thread, (void *)pool);
printf("start thread %ld.\n", pool->thread[i]);
}
//为管理者线程创建线程,调用func_adjust函数
pthread_create(&(pool->adjust_thread), NULL, func_adjust_thread, (void *)pool);
//malloc出queue_max_size个task_queue_t
pool->task_queue = (task_queue_t *)malloc(sizeof(task_queue_t) * (pool->queue_max_size));
if (pool->task_queue == NULL) {
printf("task_queue malloc failed");
break;
}
return pool;
} while(0); // 只执行一次
threadpool_free(pool); // 若前面代码调用失败,free整个空间
return NULL;
}
threadpool_add()函数向任务队列中添加任务
- 添加任务
- 发出任务队列不为空的信号
int threadpool_add(threadpool_t *pool, void *(*function)(void *), void *arg) {
pthread_mutex_lock(&(pool->lock));
if (pool->shutdown == 1) {
pthread_mutex_unlock(&(pool->lock));
return -1;
}
while(pool->queue_size == pool->queue_max_size) {
pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
}
if (pool->task_queue[pool->queue_rear].arg != NULL) { //防止内存泄露
free(pool->task_queue[pool->queue_rear].arg);
pool->task_queue[pool->queue_rear].arg = NULL;
}
pool->task_queue[pool->queue_rear].function = function;
pool->task_queue[pool->queue_rear].arg = arg;
pool->queue_rear = (pool->queue_rear + 1) % (pool->queue_max_size);
pool->queue_size++;
pthread_cond_signal(&(pool->queue_not_empty));
pthread_mutex_unlock(&(pool->lock));
return 0;
}
func_thread():普通线程的回调函数
适用场景
- 线程池初始化时创建
min_thread_num
个线程 - 在管理者线程的回调函数中当需要增加线程池线程数量时
shutdown == 1
或者wait_exit_thread_num > 0
需要退出线程时,唤醒queue_not_empty
,执行pthread_exit(NULL)
流程
- 将一个任务出队
- 将任务放入线程池中执行,这一步比较抽象,转换成代码就是
busy_thread_num++
,同时前后加解锁 - 任务执行完出线程池,转换成代码就是
busy_thread_num--
,同时前后加解锁
void* func_thread(void *arg) { //
threadpool_t *pool = (threadpool_t *)arg;
task_queue_t task;
while(1) {
pthread_mutex_lock(&(pool->lock));
while ((pool->queue_size) == 0 && (pool->shutdown) == 0) { //task_queue为空
printf("thread %ld is waiting.\n", pthread_self());
pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
if (pool->wait_exit_thread_num > 0) { //shudown == 0时结束线程直到只剩最少的线程数
pool->wait_exit_thread_num--;
if (pool->live_thread_num > pool->min_thread_num) {
printf("thread %ld is exiting.\n", pthread_self());
pool->live_thread_num--;
pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL); // 先解锁再exit
}
}
}
while(pool->shutdown) { //shutdown == 1时结束全部线程
pthread_mutex_unlock(&(pool->lock));
printf("thread %ld is exiting.\n", pthread_self());
pthread_exit(NULL);
}
//出队
task.function = pool->task_queue[pool->queue_front].function;
task.arg = pool->task_queue[pool->queue_front].arg;
pool->queue_front = (pool->queue_front + 1) % (pool->queue_max_size); // 环形队列
pool->queue_size--;
pthread_cond_broadcast(&(pool->queue_not_full));
pthread_mutex_unlock(&(pool->lock));
//入线程池
printf("thread %ld is start working.\n",pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thread_num++;
pthread_mutex_unlock(&(pool->thread_counter));
task.function(task.arg); //
//处理完任务
printf("thread %ld is end working.\n", pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thread_num--;
pthread_mutex_unlock(&(pool->thread_counter));
}
pthread_exit(NULL);
}
func_adjust_thread:管理者线程的回调函数
- 何时添加线程池中的线程
- 何时减少线程池中的线程。这里减少线程池中的线程的方法很有意思。即先增加
wait_exit_thread_num
,再唤醒queue_not_empty
void* func_adjust_thread(void* arg) {
threadpool_t *pool = (threadpool_t *)arg;
//ques:不进行值的修改为何还需要锁
while(pool->shutdown == 0) { //线程池未关闭
sleep(DEFAULT_TIME);
pthread_mutex_lock(&(pool->lock));
int live_thread_num = pool->live_thread_num;
int max_thread_num = pool->max_thread_num;
int min_thread_num = pool->min_thread_num;
int queue_size = pool->queue_size;
pthread_mutex_unlock(&(pool->lock));
pthread_mutex_lock(&(pool->thread_counter));
int busy_thread_num = pool->live_thread_num;
pthread_mutex_unlock(&(pool->thread_counter));
//add
if (queue_size > MIN_WAIT_TASK_NUM && live_thread_num < max_thread_num) {
int add = 0;
pthread_mutex_lock(&(pool->lock));
for (int i = 0; (i < max_thread_num) && (add < DEFAULT_STEP) && (live_thread_num < max_thread_num); i++) { //因为并发,所以这里也需要保证<max_thread_num
if (pool->thread[i] == 0 ) {
pthread_create(&(pool->thread[i]), NULL, func_thread, (void*)pool);
add++;
pool->live_thread_num++; // don't forget
}
}
pthread_mutex_unlock(&(pool->lock));
}
//sub
if (live_thread_num > (2 * busy_thread_num) && live_thread_num > min_thread_num) {
pthread_mutex_lock(&(pool->lock));
pool->wait_exit_thread_num = DEFAULT_STEP; // 修改的时候一定要加锁
pthread_mutex_unlock(&(pool->lock));
for (int i = 0; i < DEFAULT_STEP; i++) {
pthread_cond_signal(&(pool->queue_not_empty));
}
}
}
return NULL;
}
完整代码
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#define DEFAULT_STEP 10
#define MIN_WAIT_TASK_NUM 10
#define DEFAULT_TIME 10
typedef struct {
void *(*function)(void *); //回调函数
void *arg; //参数
} task_queue_t; //任务
struct threadpool_t {
pthread_mutex_t lock;
pthread_mutex_t thread_counter; //busy_thread_num修改时加解锁
pthread_cond_t queue_not_full;
pthread_cond_t queue_not_empty;
pthread_t *thread; //线程数组
pthread_t adjust_thread; //管理者线程管理线程池的线程数量
task_queue_t *task_queue; //任务队列数组
int min_thread_num;
int max_thread_num;
int live_thread_num;
int busy_thread_num;
int wait_exit_thread_num; //等待销毁的线程数
int queue_front;
int queue_rear;
int queue_size;
int queue_max_size;
int shutdown; //shutdown == 0 线程池开,shutdown == 1线程池关
};
int threadpool_free(threadpool_t *pool);
int threadpool_destory(threadpool_t *pool);
void* func_thread(void *arg) { //
threadpool_t *pool = (threadpool_t *)arg;
task_queue_t task;
while(1) {
pthread_mutex_lock(&(pool->lock));
while ((pool->queue_size) == 0 && (pool->shutdown) == 0) { //task_queue为空
printf("thread %ld is waiting.\n", pthread_self());
pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
if (pool->wait_exit_thread_num > 0) { //shudown == 0时结束线程直到只剩最少的线程数
pool->wait_exit_thread_num--;
if (pool->live_thread_num > pool->min_thread_num) {
printf("thread %ld is exiting.\n", pthread_self());
pool->live_thread_num--;
pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL); // 先解锁再exit
}
}
}
while(pool->shutdown) { //shutdown == 1时结束全部线程
pthread_mutex_unlock(&(pool->lock));
printf("thread %ld is exiting.\n", pthread_self());
pthread_exit(NULL);
}
//出队
task.function = pool->task_queue[pool->queue_front].function;
task.arg = pool->task_queue[pool->queue_front].arg;
pool->queue_front = (pool->queue_front + 1) % (pool->queue_max_size); // 环形队列
pool->queue_size--;
pthread_cond_broadcast(&(pool->queue_not_full));
pthread_mutex_unlock(&(pool->lock));
//入线程池
printf("thread %ld is start working.\n",pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thread_num++;
pthread_mutex_unlock(&(pool->thread_counter));
task.function(task.arg); //
//处理完任务
printf("thread %ld is end working.\n", pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thread_num--;
pthread_mutex_unlock(&(pool->thread_counter));
}
pthread_exit(NULL);
}
void* func_adjust_thread(void* arg) {
threadpool_t *pool = (threadpool_t *)arg;
//ques:不进行值的修改为何还需要锁
while(pool->shutdown == 0) { //线程池未关闭
sleep(DEFAULT_TIME);
pthread_mutex_lock(&(pool->lock));
int live_thread_num = pool->live_thread_num;
int max_thread_num = pool->max_thread_num;
int min_thread_num = pool->min_thread_num;
int queue_size = pool->queue_size;
pthread_mutex_unlock(&(pool->lock));
pthread_mutex_lock(&(pool->thread_counter));
int busy_thread_num = pool->live_thread_num;
pthread_mutex_unlock(&(pool->thread_counter));
//add
if (queue_size > MIN_WAIT_TASK_NUM && live_thread_num < max_thread_num) {
int add = 0;
pthread_mutex_lock(&(pool->lock));
for (int i = 0; (i < max_thread_num) && (add < DEFAULT_STEP) && (live_thread_num < max_thread_num); i++) { //因为并发,所以这里也需要保证<max_thread_num
if (pool->thread[i] == 0 ) {
pthread_create(&(pool->thread[i]), NULL, func_thread, (void*)pool);
add++;
pool->live_thread_num++; // don't forget
}
}
pthread_mutex_unlock(&(pool->lock));
}
//sub
if (live_thread_num > (2 * busy_thread_num) && live_thread_num > min_thread_num) {
pthread_mutex_lock(&(pool->lock));
pool->wait_exit_thread_num = DEFAULT_STEP; // 修改的时候一定要加锁
pthread_mutex_unlock(&(pool->lock));
for (int i = 0; i < DEFAULT_STEP; i++) {
pthread_cond_signal(&(pool->queue_not_empty));
}
}
}
return NULL;
}
threadpool_t *threadpool_create(int min_thread_num, int max_thread_num, int queue_max_size){
struct threadpool_t *pool = (threadpool_t *)malloc(sizeof(threadpool_t));
do{
if (pool == NULL) {
printf("pool malloc failed");
break;
}
pool->min_thread_num = min_thread_num;
pool->max_thread_num = max_thread_num;
pool->live_thread_num = min_thread_num;
pool->busy_thread_num = 0;
pool->wait_exit_thread_num = 0;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->queue_size = 0;
pool->queue_max_size = queue_max_size;
pool->shutdown = 0;
if (pthread_mutex_init(&(pool->lock), NULL) != 0 ||
pthread_mutex_init(&(pool->thread_counter), NULL) != 0 ||
pthread_cond_init(&(pool->queue_not_full), NULL) != 0 ||
pthread_cond_init(&(pool->queue_not_empty), NULL) != 0 ) {
printf("init the lock or cond failed");
break;
}
pool->thread = (pthread_t *)malloc(sizeof(pthread_t) * max_thread_num);
if (pool->thread == NULL) {
printf("thread malloc failed");
break;
}
memset(pool->thread, 0, sizeof(pthread_t) * max_thread_num);
for (int i = 0; i < min_thread_num; i++) {
pthread_create(&(pool->thread[i]), NULL, func_thread, (void *)pool);
printf("start thread %ld.\n", pool->thread[i]);
}
pthread_create(&(pool->adjust_thread), NULL, func_adjust_thread, (void *)pool);
pool->task_queue = (task_queue_t *)malloc(sizeof(task_queue_t) * (pool->queue_max_size));
if (pool->task_queue == NULL) {
printf("task_queue malloc failed");
break;
}
return pool;
} while(0); // 只执行一次
threadpool_free(pool); // 若前面代码调用失败,free整个空间
return NULL;
}
int threadpool_add(threadpool_t *pool, void *(*function)(void *), void *arg) {
pthread_mutex_lock(&(pool->lock));
if (pool->shutdown == 1) {
pthread_mutex_unlock(&(pool->lock));
return -1;
}
while(pool->queue_size == pool->queue_max_size) {
pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
}
if (pool->task_queue[pool->queue_rear].arg != NULL) { //important
free(pool->task_queue[pool->queue_rear].arg);
pool->task_queue[pool->queue_rear].arg = NULL;
}
pool->task_queue[pool->queue_rear].function = function;
pool->task_queue[pool->queue_rear].arg = arg;
pool->queue_rear = (pool->queue_rear + 1) % (pool->queue_max_size);
pool->queue_size++;
pthread_cond_signal(&(pool->queue_not_empty));
pthread_mutex_unlock(&(pool->lock));
return 0;
}
int threadpool_free(threadpool_t *pool) {
if (pool == NULL) return -1;
if (pool->task_queue) {
free(pool->task_queue);
}
if (pool->thread) {
free(pool->thread);
}
pthread_mutex_lock(&(pool->lock));
pthread_mutex_destroy(&(pool->lock));
pthread_mutex_lock(&(pool->thread_counter));
pthread_mutex_destroy(&(pool->thread_counter));
pthread_cond_destroy(&(pool->queue_not_empty));
pthread_cond_destroy(&(pool->queue_not_full));
free(pool); // free释放了一个结构体,但是其中的指针还可以访问
pool = NULL;
return 0;
}
int threadpool_destory(threadpool_t *pool) { //此函数为什么不加锁
if (pool == NULL) return -1;
pool->shutdown = 1;
pthread_join(pool->adjust_thread, NULL);
for (int i = 0; i < pool->live_thread_num; i++) {
pthread_cond_broadcast(&(pool->queue_not_empty));
}
for (int i = 0; i < pool->live_thread_num; i++) { // live_thread_num <= min_thread_num时???
pthread_join(pool->thread[i], NULL);
}
threadpool_free(pool);
return 0;
}
void* process (void *arg) {
printf("thread %ld is working %ld task.\n", pthread_self(), (intptr_t)arg);
sleep(1);
printf("task %ld is end.\n", (intptr_t)arg);
return NULL;
}
int main() {
struct threadpool_t *threadpool = threadpool_create(3, 100, 100);
printf("threadpool init.\n");
intptr_t nums[80];
for (intptr_t i = 0; i < 80; i++) {
nums[i] = i; //task;
printf("add task %ld\n", nums[i]);
threadpool_add(threadpool, process, (void *)nums[i]); // 线程池,回调函数,泛型参数
}
sleep(10);
threadpool_destory(threadpool);
return 0;
}