写在前面:
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的。在传统的多线程服务器模型中是这样实现的:一旦有个请求到达,就创建一个新的线程,由该线程执行任务,任务执行完毕之后,线程就退出。这就是"即时创建,即时销毁"的策略。尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数非常频繁,那么服务器就将处于一个不停的创建线程和销毁线程的状态。这笔开销是不可忽略的,尤其是线程执行的时间非常非常短的情况。
线程池就是为了解决上述问题的,它的实现原理是这样的:在应用程序启动之后,就马上创建一定数量的线程,放入空闲的队列中。这些线程都是处于阻塞状态,这些线程只占一点内存,不占用CPU。当任务到来后,线程池将选择一个空闲的线程,将任务传入此线程中运行。当所有的线程都处在处理任务的时候,线程池将自动创建一定的数量的新线程,用于处理更多的任务。执行任务完成之后线程并不退出,而是继续在线程池中等待下一次任务。当大部分线程处于阻塞状态时,线程池将自动销毁一部分的线程,回收系统资源。
正文:下面的代码是对线程池的一个实现,只不过没有对线程池进行“扩容”和“瘦身”的处理,可以在此基础上进行扩展。
代码实现:注释已经尽可能的详细了
#include "stdio.h"
#include
#include
typedef enum
{
IMMEDIATA_SHUTDOWN = 1,
FORCE_SHUTDOWN = 2,
}THREADPOOL_SHUTDOWN_TYPE_e;
typedef struct
{
void (*function)(void * args);
void *args;
}threadpool_task_t; //定义任务处理函数的类型
typedef struct
{
pthread_mutex_t mutex; //互斥锁,线程内使用threadpool_t时需要上锁
pthread_cond_t notify; //线程间用于通知的条件变量
pthread_t* p_thread;//线程数组,这里用来存储数组的首地址
threadpool_task_t* p_queue; //任务队列数组,这里存储数组首地址
int thread_count;//要创建的线程的大小
int queue_size;//任务队列的大小
int head;//队列的第一个任务的位置
int tail;//队列的最后一个队列的位置
int count;//任务队列中的任务数,即任务队列中等待运行的任务数
int shutdown;//0:线程池不关闭;1:线程池关闭
int start_count;//开始创建的线程池的线程数
}threadpool_t;
void * threadpool_thread(void * args);
//线程池创建函数
//参数:thread_count:要创建的线程池中线程个数的大小
// queue_size: 任务队列的大小
threadpool_t * threadPoolCreate(int thread_count,int queue_size)
{
threadpool_t * p_pool = NULL;
int i = 0;
//申请内存创建线程池对象
p_pool = (threadpool_t *)malloc(sizeof(threadpool_t));
if(NULL == p_pool)
{
printf("thread poll create error\n");
return NULL;
}
p_pool ->thread_count = 0;
p_pool ->queue_size = queue_size;
p_pool ->head = 0;
p_pool ->tail = 0;
p_pool ->count = 0;
p_pool ->shutdown = 0;
//创建线程池数组
p_pool ->p_thread = (pthread_t *)malloc(thread_count * sizeof(pthread_t));
if(NULL == p_pool ->p_thread)
{
printf("pthread arry create error\n");
return NULL;
}
//创建任务队列数组
p_pool ->p_queue = (threadpool_task_t *)malloc(queue_size * sizeof(threadpool_task_t));
if(NULL == p_pool ->p_queue)
{
printf("p_queue arry create error\n");
return NULL;
}
//创建互斥锁和条件变量
pthread_mutex_init(&(p_pool ->mutex),NULL);
pthread_cond_init(&(p_pool ->notify),NULL);
//开始创建线程
for(i = 0;i < thread_count;i ++)
{
if(pthread_create(&(p_pool ->p_thread[i]), NULL,threadpool_thread, (void *)p_pool) == 0)
{
p_pool ->start_count ++;
p_pool ->thread_count ++;
}
else
{
threadpool_destroy(p_pool);
}
}
//printf("p_pool ->start_count = %d\t, p_pool ->queue_size = %d\n",p_pool ->start_count,p_pool ->queue_size);
return p_pool;
}
//添加任务到线程池
//参数:p_pool 线程池对象指针
// p_task_queue 任务队列类型
//返回: 添加成功:0;失败 -1
int threadpool_add(threadpool_t * p_pool,threadpool_task_t *p_task_queue)
{
int next = 0;
if((NULL == p_pool)||(NULL == p_task_queue))
{
printf("%s:params error -1",__FUNCTION__);
return -1;
}
//上锁
pthread_mutex_lock(&(p_pool ->mutex));
//计算下一个存储任务队列的位置
next = p_pool ->tail + 1;
next = (next >= p_pool ->queue_size) ? 0: next;
//判断队列是否满了
if(p_pool ->count >= p_pool ->queue_size)
{
printf("task queue is full \n");
return -1;
}
//判断当前线程池是否关闭
if(p_pool ->shutdown)
{
printf("thread pool is shutdown\n");
return -1;
}
//将任务队列添加到线程池
p_pool ->p_queue[ p_pool ->tail].function = p_task_queue->function;
p_pool ->p_queue[ p_pool ->tail].args = p_task_queue->args;
p_pool ->count ++;
p_pool ->tail = next;
//发出signal,表示有任务队列添加进来了
pthread_cond_signal(&(p_pool ->notify));
//释放互斥锁
pthread_mutex_unlock(&(p_pool ->mutex));
//printf("%s:p_pool ->count = %d\t,p_pool ->tail = %d\t,p_pool ->queue_size=%d\n",__FUNCTION__,p_pool ->count,p_pool ->tail,p_pool ->queue_size);
return 0;
}
//释放线程池
int thread_pool_free(threadpool_t * p_pool)
{
if(NULL == p_pool)
{
return 0;
}
if(p_pool ->p_thread)
{
//释放线程数组
free(p_pool ->p_thread);
//释放任务队列数组
free(p_pool ->p_queue);
//销毁互斥锁
pthread_mutex_lock(&(p_pool->mutex));
pthread_mutex_destroy(&(p_pool->mutex));
pthread_cond_destroy(&(p_pool->notify));
}
free(p_pool);
return 0;
}
int threadpool_destroy(threadpool_t *p_pool)
{
int i, err = 0;
if(p_pool == NULL) {
return 0;
}
/* 取得互斥锁资源 */
if(pthread_mutex_lock(&(p_pool->mutex)) != 0) {
return -1;
}
do {
/* Already shutting down */
/* 判断是否已在其他地方关闭 */
if(p_pool->shutdown) {
err = 1;
break;
}
/* 获取指定的关闭方式 */
p_pool->shutdown = (FORCE_SHUTDOWN) ?
FORCE_SHUTDOWN : IMMEDIATA_SHUTDOWN;
/* Wake up all worker threads */
/* 唤醒所有因条件变量阻塞的线程,并释放互斥锁 */
if((pthread_cond_broadcast(&(p_pool->notify)) != 0) ||
(pthread_mutex_unlock(&(p_pool->mutex)) != 0)) {
err = 2;
break;
}
/* Join all worker thread */
/* 等待所有线程结束 */
for(i = 0; i < p_pool->thread_count; i++) {
if(pthread_join(p_pool->p_thread[i], NULL) != 0) {
err = 3;
}
}
/* 同样是 do{...} while(0) 结构*/
} while(0);
/* Only if everything went well do we deallocate the pool */
if(!err) {
/* 释放内存资源 */
thread_pool_free(p_pool);
}
return err;
}
//线程处理函数
void * threadpool_thread(void * args)
{
threadpool_t * p_pool = (threadpool_t *)args;
threadpool_task_t task;
while(1)
{
//上锁
pthread_mutex_lock(&(p_pool ->mutex));
//如果队列为空并且线程池不关闭的时候,就在这里一直等待
while((p_pool ->count == 0)&&(p_pool ->shutdown == 0))
{
pthread_cond_wait(&(p_pool->notify), &(p_pool->mutex));
}
//如果线程池关闭
if((p_pool->shutdown == IMMEDIATA_SHUTDOWN) ||
((p_pool->shutdown == FORCE_SHUTDOWN) &&
(p_pool->count == 0))) {
printf("thread out\n");
break;
}
//获取任务队列的第一个任务
task.function = p_pool ->p_queue[p_pool ->head].function;
task.args = p_pool ->p_queue[p_pool ->head].args;
//更新任务头和任务总数
p_pool ->head ++;
p_pool ->head = (p_pool ->head >= p_pool->queue_size)?0:p_pool ->head;
p_pool ->count --;
//释放互斥锁
pthread_mutex_unlock(&(p_pool ->mutex));
//运行任务
(*(task.function))(task.args);
//printf("%s:p_pool ->count = %d\n",__FUNCTION__,p_pool ->count);
}
//本线程结束,线程数也相应更新
p_pool ->start_count --;
//printf("%s:p_pool ->start_count = %d\n",__FUNCTION__,p_pool ->start_count);
pthread_mutex_unlock(&(p_pool->mutex));
pthread_exit(NULL);
return NULL;
}
void task_fun1(void * args)
{
printf("this is a test 1\n");
}
void task_fun2(void * args)
{
printf("this is a test 2\n");
}
void task_fun3(void * args)
{
printf("this is a test 3\n");
}
int main(void)
{
pthread_mutex_t lock;
threadpool_t * p_pool = threadPoolCreate(10,36);
threadpool_task_t task_t[3];
if(NULL == p_pool)
{
printf("thread pool create error\n");
return -1;
}
/* 初始化互斥锁 */
pthread_mutex_init(&lock, NULL);
task_t[0].function = task_fun1;
task_t[1].function = task_fun2;
task_t[2].function = task_fun3;
//将这三个任务添加到线程池中
task_t[0].args = task_t[1].args = task_t[2].args = NULL;
pthread_mutex_lock(&lock);
threadpool_add(p_pool,&task_t[0]);
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
threadpool_add(p_pool,&task_t[1]);
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
threadpool_add(p_pool,&task_t[2]);
pthread_mutex_unlock(&lock);
while(1)
{
sleep(1);
}
return 0;
}
测试结果: