Linux 网络编程 全解(八)--------线程池的实现

写在前面:

    大多数的网络服务器,包括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;
}

测试结果:

Linux 网络编程 全解(八)--------线程池的实现_第1张图片

 

 

 

你可能感兴趣的:(Linux网络编程)