目录
(3)写线程函数(固定格式):先加互斥锁;将任务队列中任务取出执行;没有任务,就等待队列不为空;取出任务后,执行任务函数;队列头指针加1,任务数减1;然后解锁;
(4)写任务进队列函数(重点):先加互斥锁;等待队列不满(链式队列不存在);将任务放入人户队列中(任务包含:任务函数、函数参数);队列尾指针加1,任务数加1;然后解锁;
(5)写任务函数功能(重点:可以调用功能不同的函数):任务函数可以功能各不相同(函数名不同),但是参数与结构必须相同;
(6)销毁线程池(固定格式):等待队列为空;唤醒所以线程;释放所有线程;销毁互斥锁和条件变量;将队列置空;释放pool;
一、线程池概述
1、为什么要使用线程池?
一个进程所支持的线程是有限的(受限);
线程的创建与销毁是有一定的开销的(当线程数目多时);
(内存池是解决频繁malloc产生的开销问题;对象池是解决对象频繁分配所带来的开销问题)
2、线程池的核心
任务队列:用来存放客户端所请求的服务(所要完成的功能函数)
线程池:用于存放线程(还包含线程数量,任务队列头/尾指针,任务队列大小,互斥锁,条件变量,线程销毁标志位等)
当任务队列为空时,线程池里的线程阻塞等待;
任务队列不为空时,线程池里的线程处理任务;
任务队列为满时,不能再次新增任务;
二、线程池的实现
1、线程池实现的一般步骤:
(1)完成任务队列结构体、线程池结构体
最完整版:
struct job{
void *(*func)(void *arg); //队列中的函数
void *arg; //功能函数的参数
struct job *next; // 指向下一个节点
};
struct threadpool{
int thread_num; //线程的个数
pthread_t *ids; //线程的id
int queue_max_num; //队列的最大容量
int queue_cur_num; //队列正在执行的个数
struct job *head; //队列的头
struct job *tail; //队列的尾
pthread_mutex_t mutex; //锁队列的增与减
pthread_cond_t not_empty; //非空
pthread_cond_t not_full; //非满
pthread_cond_t queue_empty; //队列为空
};
注意:队列函数可以按要求更改;线程池结构体(队列非满(not_full)可以省略(链式队列无满情况),队列为空(queue_empty)也可以去掉,队列最大容量(queue_max_num)也可以去掉,链式队列无最大容量)也可更改;
(2)初始化线程池:将线程池内部变量注意初始化;
(3)写线程函数(固定格式):先加互斥锁;将任务队列中任务取出执行;没有任务,就等待队列不为空;取出任务后,执行任务函数;队列头指针加1,任务数减1;然后解锁;
(4)写任务进队列函数(重点):先加互斥锁;等待队列不满(链式队列不存在);将任务放入人户队列中(任务包含:任务函数、函数参数);队列尾指针加1,任务数加1;然后解锁;
(5)写任务函数功能(重点:可以调用功能不同的函数):任务函数可以功能各不相同(函数名不同),但是参数与结构必须相同;
(6)销毁线程池(固定格式):等待队列为空;唤醒所以线程;释放所有线程;销毁互斥锁和条件变量;将队列置空;释放pool;
2、代码实现
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct job{
void *(*func)(void *arg); //队列中的函数
void *arg; //功能函数的参数
struct job *next; // 指向下一个节点
};
struct threadpool{
int thread_num; //线程的个数
pthread_t *ids; //线程的id
int queue_max_num; //队列的最大容量
int queue_cur_num; //队列正在执行的个数
struct job *head; //队列的头
struct job *tail; //队列的尾
pthread_mutex_t mutex; //锁队列的增与减
pthread_cond_t not_empty; //非空
pthread_cond_t not_full; //非满
pthread_cond_t queue_empty; //队列为空
};
void *thread_function(void *arg) //线程函数
{
struct threadpool *pool = (struct threadpool *)arg;
struct job *fjob = NULL;
while (1)
{
pthread_mutex_lock(&(pool->mutex));
if (pool->queue_cur_num == 0)
{
pthread_cond_wait(&(pool->not_empty), &(pool->mutex));
}
fjob = pool->head;
pool->queue_cur_num--;
if (pool->queue_cur_num != pool->queue_max_num)
{
pthread_cond_signal(&(pool->not_full));
}
if (pool->queue_cur_num == 0)
{
pool->head = pool->tail = NULL;
pthread_cond_signal(&(pool->queue_empty));
}
else
{
pool->head = pool->head->next;
}
pthread_mutex_unlock(&(pool->mutex));
(*(fjob->func))(fjob->arg);
free(fjob);
fjob = NULL;
}
}
struct threadpool *threadpool_init(int thread_num, int queue_max_num) //初始化线程池
{
struct threadpool *pool = (struct threadpool *)malloc(sizeof(struct threadpool));
pool->thread_num = thread_num;
pool->ids = (pthread_t *)malloc(sizeof(pthread_t)*thread_num);
pool->queue_max_num = queue_max_num;
pool->queue_cur_num = 0;
pool->head = NULL;
pool->tail = NULL;
pthread_mutex_init(&(pool->mutex), NULL);
pthread_cond_init(&(pool->queue_empty), NULL);
pthread_cond_init(&(pool->not_empty), NULL);
pthread_cond_init(&(pool->not_full), NULL);
for (int i = 0; i < pool->thread_num; i++)
{
pthread_create(&(pool->ids[i]), NULL, (void *)thread_function, (void *)pool);
}
return pool;
}
void *work_function(void *arg) //队列函数
{
char *p = (char *)arg;
printf("hello word!%s\n", p);
printf("welcome jestc!%s\n", p);
sleep(1);
}
void threadpool_add_job(struct threadpool *pool, void *(*work_function)(void *), void *arg) //向队列中添加任务节点
{
pthread_mutex_lock(&(pool->mutex));
while (pool->queue_cur_num == pool->queue_max_num)
{
pthread_cond_wait(&(pool->not_full), &(pool->mutex));
}
struct job * fjob = (struct job *)malloc(sizeof(struct job));
fjob->next = NULL;
fjob->func = work_function;
fjob->arg = arg;
if (pool->head == NULL)
{
pool->head = pool->tail = fjob;
pthread_cond_signal(&(pool->not_empty));
}
else
{
pool->tail->next = fjob;
pool->tail = fjob;
}
pool->queue_cur_num++;
pthread_mutex_unlock(&(pool->mutex));
}
void threadpool_destory(struct threadpool *pool) //释放线程池
{
pthread_mutex_lock(&(pool->mutex));
while (1)
{
pthread_cond_wait(&(pool->queue_empty), &(pool->mutex));
}
pthread_mutex_unlock(&(pool->mutex));
pthread_cond_signal(&(pool->not_empty)); //唤醒线程池
pthread_cond_signal(&(pool->not_full));
for (int i = 0; i < pool->thread_num; i++)
{
pthread_join(pool->ids[i], NULL);
}
pthread_mutex_destroy(&(pool->mutex));
pthread_cond_destroy(&(pool->not_empty));
pthread_cond_destroy(&(pool->not_full));
pthread_cond_destroy(&(pool->queue_empty));
free(pool->ids);
struct job *temp = NULL;
while (pool->head != NULL)
{
temp = pool->head;
pool->head = temp->next;
free(temp);
}
free(pool);
}
int main(int argc, char *argv[])
{
struct threadpool * pool = threadpool_init(5, 100); //创建线程池
threadpool_add_job(pool, (void *)work_function, "1"); //向队列中添加任务节点
threadpool_add_job(pool, (void *)work_function, "2");
threadpool_add_job(pool, (void *)work_function, "3");
threadpool_add_job(pool, (void *)work_function, "4");
threadpool_add_job(pool, (void *)work_function, "5");
threadpool_add_job(pool, (void *)work_function, "6");
threadpool_add_job(pool, (void *)work_function, "7");
threadpool_add_job(pool, (void *)work_function, "8");
threadpool_add_job(pool, (void *)work_function, "9");
threadpool_add_job(pool, (void *)work_function, "10");
threadpool_add_job(pool, (void *)work_function, "11"); //向队列中添加任务节点
threadpool_add_job(pool, (void *)work_function, "12");
threadpool_add_job(pool, (void *)work_function, "13");
threadpool_add_job(pool, (void *)work_function, "14");
threadpool_add_job(pool, (void *)work_function, "15");
threadpool_add_job(pool, (void *)work_function, "16");
threadpool_add_job(pool, (void *)work_function, "17");
threadpool_add_job(pool, (void *)work_function, "18");
threadpool_add_job(pool, (void *)work_function, "19");
threadpool_add_job(pool, (void *)work_function, "20");
threadpool_destory(pool);
return 0;
}
注意:任务函数金队列和任务函数尤为重要;