线程池的原理与实现详解.docx
《线程池的原理与实现详解.docx》由会员分享,可在线阅读,更多相关《线程池的原理与实现详解.docx(16页珍藏版)》请在冰豆网上搜索。
线程池的原理与实现详解
线程池的原理与实现详解
一.线程池的简介
通常我们使用多线程的方式是,需要时创建一个新的线程,在这个线程里执行特定的任务,然后在任务完成后退出。
这在一般的应用里已经能够满足我们应用的需求,毕竟我们并不是什么时候都需要创建大量的线程,并在它们执行一个简单的任务后销毁。
但是在一些web、email、database等应用里,比如彩铃,我们的应用在任何时候都要准备应对数目巨大的连接请求,同时,这些请求所要完成的任务却又可能非常的简单,即只占用很少的处理时间。
这时,我们的应用有可能处于不停的创建线程并销毁线程的状态。
虽说比起进程的创建,线程的创建时间已经大大缩短,但是如果需要频繁的创建线程,并且每个线程所占用的处理时间又非常简短,则线程创建和销毁带给处理器的额外负担也是很可观的。
线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。
一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。
应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。
如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。
当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。
因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。
基于上面的技术,线程池将频繁创建和销毁线程所带来的开销分摊到了每个具体执行的任务上,执行的次数越多,则分摊到每个任务上的开销就越小。
当然,如果线程创建销毁所带来的开销与线程执行任务的开销相比微不足道,可以忽略不计,则线程池并没有使用的必要。
比如,FTP、Telnet等应用时。
二.线程池的设计
下面利用C语言来实现一个简单的线程池,为了使得这个线程池库使用起来更加方便,特在C实现中加入了一些OO的思想,与Objective-C不同,它仅仅是使用了struct来模拟了c++中的类,其实这种方式在linux内核中大量可见。
在这个库里,与用户有关的接口主要有:
复制代码代码如下:
typedefstructtp_work_desc_stp_work_desc;//应用线程执行任务时所需要的一些信息
typedefstructtp_work_stp_work;//线程执行的任务
typedefstructtp_thread_info_stp_thread_info;//描述了各个线程id,是否空闲,执行的任务等信息
typedefstructtp_thread_pool_stp_thread_pool;//有关线程池操作的接口信息
//threadparm
structtp_work_desc_s{
……
};
//basethreadstruct
structtp_work_s{
//mainprocessfunction.userinterface
void(*process_job)(tp_work*this,tp_work_desc*job);
};
tp_thread_pool*creat_thread_pool(intmin_num,intmax_num);tp_work_desc_s表示应用线程执行任务时所需要的一些信息,会被当作线程的参数传递给每个线程,依据应用的不同而不同,需要用户定义结构的内容。
tp_work_s就是我们希望线程执行的任务了。
当我们申请分配一个新的线程时,首先要明确的指定这两个结构,即该线程完成什么任务,并且完成这个任务需要哪些额外的信息。
接口函数creat_thread_pool用来创建一个线程池的实例,使用时需要指定该线程池实例所能容纳的最小线程数min_num和最大线程数max_num。
最小线程数即线程池创建时预创建的线程数目,这个数目的大小也直接影响了线程池所能起到的效果,如果指定的太小,线程池中预创建的线程很快就将分配完毕并需要创建新的线程来适应不断的请求,如果指定的太大,则将可能会有大量的空闲线程。
我们需要根据自己应用的实际需要进行指定。
描述线程池的结构如下:
复制代码代码如下:
//mainthreadpoolstruct
structtp_thread_pool_s{
TPBOOL(*init)(tp_thread_pool*this);
void(*close)(tp_thread_pool*this);
void(*process_job)(tp_thread_pool*this,tp_work*worker,tp_work_desc*job);
int(*get_thread_by_id)(tp_thread_pool*this,intid);
TPBOOL(*add_thread)(tp_thread_pool*this);
TPBOOL(*delete_thread)(tp_thread_pool*this);
int(*get_tp_status)(tp_thread_pool*this);
intmin_th_num;//minthreadnumberinthepool
intcur_th_num;//currentthreadnumberinthepool
intmax_th_num;//maxthreadnumberinthepool
pthread_mutex_ttp_lock;
pthread_tmanage_thread_id;//managethreadidnum
tp_thread_info*thread_info;//workthreadrelativethreadinfo
};
结构tp_thread_info_s描述了各个线程id、是否空闲、执行的任务等信息,用户并不需要关心它。
//threadinfo
structtp_thread_info_s{
pthread_tthread_id;//threadidnum
TPBOOLis_busy;//threadstatus:
true-busy;flase-idle
pthread_cond_tthread_cond;
pthread_mutex_tthread_lock;
tp_work*th_work;
tp_work_desc*th_job;
};tp_thread_pool_s结构包含了有关线程池操作的接口和变量。
在使用creat_thread_pool返回一个线程池实例之后,首先要使用明确使用init接口对它进行初始化。
在这个初始化过程中,线程池会预创建指定的最小线程数目的线程,它们都处于阻塞状态,并不损耗CPU,但是会占用一定的内存空间。
同时init也会创建一个线程池的管理线程,这个线程会在线程池的运行周期内一直执行,它将定时的查看分析线程池的状态,如果线程池中空闲的线程过多,它会删除部分空闲的线程,当然它并不会使所有线程的数目小于指定的最小线程数。
在已经创建并初始化了线程池之后,我们就可以指定tp_work_desc_s和tp_work_s结构,并使用线程池的process_job接口来执行它们。
这些就是我们使用这个线程池时所需要了解的所有东西。
如果不再需要线程池,可以使用close接口销毁它。
三.实现代码
Thread-pool.h(头文件):
复制代码代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<pthread.h>
#include<signal.h>#ifndefTPBOOL
typedefintTPBOOL;
#endif#ifndefTRUE
#defineTRUE1
#endif#ifndefFALSE
#defineFALSE0
#endif#defineBUSY_THRESHOLD0.5//(busythread)/(allthreadthreshold)
#defineMANAGE_INTERVAL5//tpmanagethreadsleepintervaltypedefstructtp_work_desc_stp_work_desc;
typedefstructtp_work_stp_work;
typedefstructtp_thread_info_stp_thread_info;
typedefstructtp_thread_pool_stp_thread_pool;//threadparm
structtp_work_desc_s{
char*inum;//callin
char*onum;//callout
intchnum;//channelnum
};//basethreadstruct
structtp_work_s{
//mainprocessfunction.userinterface
void(*process_job)(tp_work*this,tp_work_desc*job);
};//threadinfo
structtp_thread_info_s{
pthread_tthread_id;//threadidnum
TPBOOLis_busy;//threadstatus:
true-busy;flase-idle
pthread_cond_tthread_cond;
pthread_mutex_tthread_lock;
tp_work*th_work;
tp_work_desc*th_job;
};//mainthreadpoolstruct
structtp_thread_pool_s{
TPBOOL(*init)(tp_thread_pool*this);
void(*close)(tp_thread_pool*this);
void(*process_job)(tp_thread_pool*this,tp_work*worker,tp_work_desc*job);
int(*get_thread_by_id)(tp_thread_pool*this,intid);
TPBOOL(*add_thread)(tp_thread_pool*this);
TPBOOL(*delete_thread)(tp_thread_pool*this);
int(*get_tp_status)(tp_thread_pool*this);intmin_th_num;//minthreadnumberinthepool
intcur_th_num;//currentthreadnumberinthepool
intmax_th_num;//maxthreadnumberinthepool
pthread_mutex_ttp_lock;
pthread_tmanage_thread_id;//managethreadidnum
tp_thread_info*thread_info;//workthreadrelativethreadinfo
};tp_thread_pool*creat_thread_pool(intmin_num,intmax_num);Thread-pool.c(实现文件):
复制代码代码如下:
#include"thread-pool.h"staticvoid*tp_work_thread(void*pthread);
staticvoid*tp_manage_thread(void*pthread);staticTPBOOLtp_init(tp_thread_pool*this);
staticvoidtp_close(tp_thread_pool*this);
staticvoidtp_process_job(tp_thread_pool*this,tp_work*worker,tp_work_desc*job);
staticinttp_get_thread_by_id(tp_thread_pool*this,intid);
staticTPBOOLtp_add_thread(tp_thread_pool*this);
staticTPBOOLtp_delete_thread(tp_thread_pool*this);
staticinttp_get_tp_status(tp_thread_pool*this);/**
*userinterface.creatthreadpool.
*para:
*num:
minthreadnumbertobecreatedinthepool
*return:
*threadpoolstructinstancebecreatedsuccessfully
*/
tp_thread_pool*creat_thread_pool(intmin_num,intmax_num){
tp_thread_pool*this;
this=(tp_thread_pool*)malloc(sizeof(tp_thread_pool));memset(this,0,sizeof(tp_thread_pool));//initmemberfunctionponter
this->init=tp_init;
this->close=tp_close;
this->process_job=tp_process_job;
this->get_thread_by_id=tp_get_thread_by_id;
this->add_thread=tp_add_thread;
this->delete_thread=tp_delete_thread;
this->get_tp_status=tp_get_tp_status;//initmembervar
this->min_th_num=min_num;
this->cur_th_num=this->min_th_num;
this->max_th_num=max_num;
pthread_mutex_init(&this->tp_lock,NULL);//mallocmemfornumthreadinfostruct
if(NULL!
=this->thread_info)
free(this->thread_info);
this->thread_info=(tp_thread_info*)malloc(sizeof(tp_thread_info)*this->max_th_num);returnthis;
}
/**
*memberfunctionreality.threadpoolinitfunction.
*para:
*this:
threadpoolstructinstanceponter
*return:
*true:
successful;false:
failed
*/
TPBOOLtp_init(tp_thread_pool*this){
inti;
interr;//creatworkthreadandinitworkthreadinfo
for(i=0;i<this->min_th_num;i++){
pthread_cond_init(&this->thread_info[i].thread_cond,NULL);
pthread_mutex_init(&this->thread_info[i].thread_lock,NULL);err=pthread_create(&this->thread_info[i].thread_id,NULL,tp_work_thread,this);
if(0!
=err){
printf("tp_init:
creatworkthreadfailed\n");
returnFALSE;
}
printf("tp_init:
creatworkthread%d\n",this->thread_info[i].thread_id);
}//creatmanagethread
err=pthread_create(&this->manage_thread_id,NULL,tp_manage_thread,this);
if(0!
=err){
printf("tp_init:
creatmanagethreadfailed\n");
returnFALSE;
}
printf("tp_init:
creatmanagethread%d\n",this->manage_thread_id);returnTRUE;
}/**
*memberfunctionreality.threadpoolentirelyclosefunction.
*para:
*this:
threadpoolstructinstanceponter
*return:
*/
voidtp_close(tp_thread_pool*this){
inti;//closeworkthread
for(i=0;i<this->cur_th_num;i++){
kill(this->thread_info[i].thread_id,SIGKILL);
pthread_mutex_destroy(&this->thread_info[i].thread_lock);
pthread_cond_destroy(&this->thread_info[i].thread_cond);
printf("tp_close:
killworkthread%d\n",this->thread_info[i].thread_id);
}//closemanagethread
kill(this->manage_thread_id,SIGKILL);
pthread_mutex_destroy(&this->tp_lock);
printf("tp_close:
killmanagethread%d\n",this->manage_thread_id);//freethreadstruct
free(this->thread_info);
}/**
*memberfunctionreality.maininterfaceopened.
*aftergettingownworkerandjob,usermayusethefunctiontoprocessthetask.
*para:
*this:
threadpoolstructinstanceponter
*worker:
usertaskreality.
*job:
usertaskpara
*return:
*/
voidtp_process_job(tp_thread_pool*this,tp_work*worker,tp_work_desc*job){
inti;
inttmpid;//fillthis->thread_info'srelativeworkkey
for(i=0;i<this->cur_th_num;i++){
pthread_mutex_lock(&this->thread_info[i].thread_lock);
if(!
this->thread_info[i].is_busy){
printf("tp_process_job:
%dthreadidle,threadidis%d\n",i,this->thread_info[i].thread_id);
//threadstatebesetbusybeforework
this->thread_info[i].is_busy=TRUE;
pthread_mutex_unlock(&this->thread_info[i].thread_lock);this->thread_info[i].th_work=worker;
this->thread_info[i].th_job=job;printf("tp_process_job:
informingidleworkingthread%d,threadidis%d\n",i,this->thread_info[i].thread_id);
pthread_cond_signal(&this->thread_info[i].thread_cond);return;
}
else
pthread_mutex_unlock(&this->thread_info[i