但是在一些web、email、database等应用里,比如彩铃,我们的应用在任何时候都要准备应对数目巨大的连接请求,同时,这些请求所要完成的任务却又可能非常的简单,即只占用很少的处理时间。这时,我们的应用有可能处于不停的创建线程并销毁线程的状态。虽说比起进程的创建,线程的创建时间已经大大缩短,但是如果需要频繁的创建线程,并且每个线程所占用的处理时间又非常简短,则线程创建和销毁带给处理器的额外负担也是很可观的。
线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。
基于上面的技术,线程池将频繁创建和销毁线程所带来的开销分摊到了每个具体执行的任务上,执行的次数越多,则分摊到每个任务上的开销就越小。
当然,如果线程创建销毁所带来的开销与线程执行任务的开销相比微不足道,可以忽略不计,则线程池并没有使用的必要。比如,FTP、Telnet等应用时。
二。线程池的设计typedef结构tp_work_desc_s tp_work_desc; //应用线程执行任务时所需要的一些信息
typedef结构tp_work_s tp_work; //线程执行的任务
typedef结构tp_thread_info_s tp_thread_info; //描述了各个线程ID,是否空闲,执行的任务等信息
typedef结构tp_thread_pool_s tp_thread_pool; //有关线程池操作的接口信息
//线程的parm
结构tp_work_desc_s {
......
};
//基地线程结构
结构tp_work_s {
//主过程中的作用。用户界面
无效(* process_job)(tp_work *此,tp_work_desc *工作);
};
tp_thread_pool * creat_thread_pool(INT MIN_NUM,诠释MAX_NUM);
tp_work_desc_s表示应用线程执行任务时所需要的一些信息,会被当作线程的参数传递给每个线程,依据应用的不同而不同,需要用户定义结构的内容。tp_work_s就是我们希望线程执行的任务了。当我们申请分配一个新的线程时,首先要明确的指定这两个结构,即该线程完成什么任务,并且完成这个任务需要哪些额外的信息。接口函数creat_thread_pool用来创建一个线程池的实例,使用时需要指定该线程池实例所能容纳的最小线程数min_num和最大线程数max_num。最小线程数即线程池创建时预创建的线程数目,这个数目的大小也直接影响了线程池所能起到的效果,如果指定的太小,线程池中预创建的线程很快就将分配完毕并需要创建新的线程来适应不断的请求,如果指定的太大,则将可能会有大量的空闲线程。我们需要根据自己应用的实际需要进行指定。描述线程池的结构如下:
//主线程池的结构
结构tp_thread_pool_s {
TPBOOL(* INIT)(tp_thread_pool *本);
无效(*关)(tp_thread_pool *本);
无效(* process_job)(tp_thread_pool *此,tp_work *工人,tp_work_desc *工作);
INT(* get_thread_by_id)(tp_thread_pool *此,INT ID);
TPBOOL(* add_thread)(tp_thread_pool *本);
TPBOOL(* delete_thread)(tp_thread_pool *本);
INT(* get_tp_status)(tp_thread_pool *本);
INT min_th_num; 在游泳池//分线数
INT cur_th_num; //池中当前线程数
INT max_th_num; //池中的最大线程数
pthread_mutex_t的tp_lock;
的pthread_t manage_thread_id; //处理线程ID NUM
tp_thread_info *的thread_info; //工作线程的线程相关信息
};
结构tp_thread_info_s描述了各个线程id、是否空闲、执行的任务等信息,用户并不需要关心它。
//线程信息
结构tp_thread_info_s {
的pthread_t THREAD_ID; //线程ID NUM
TPBOOL is_busy; //线程状态:真忙; FLASE闲
pthread_cond_t thread_cond;
pthread_mutex_t的thread_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接口销毁它。
三。实现代码
线程pool.h(头文件):
- 的#include <stdio.h中>
- 的#include <stdlib.h中>
- #包括文件<sys / types.h中>
- 的#include <pthreads.h中>
- 的#include <signal.h中>
- #ifndef的TPBOOL
- 的typedef INT TPBOOL;
- #ENDIF
- #ifndef的真
- 的#define TRUE 1
- #ENDIF
- #ifndef的FALSE
- 的#define FALSE 0
- #ENDIF
- #定义BUSY_THRESHOLD 0.5 //(忙线)/(所有线程的阈值)
- #定义MANAGE_INTERVAL 5 // TP管理线程休眠间隔
- 的typedef 结构 tp_work_desc_s tp_work_desc;
- 的typedef 结构 tp_work_s tp_work;
- 的typedef 结构 tp_thread_info_s tp_thread_info;
- 的typedef 结构 tp_thread_pool_s tp_thread_pool;
- //线程的parm
- 结构 tp_work_desc_s {
- CHAR * INUM; //在调用
- CHAR * onum; //调用出来
- INT CHNUM; //通道NUM
- };
- //基地线程结构
- 结构 tp_work_s {
- //主过程中的作用。用户界面
- 无效 (* process_job)(tp_work * 此,tp_work_desc *工作);
- };
- //线程信息
- 结构 tp_thread_info_s {
- 的pthread_t THREAD_ID; //线程ID NUM
- TPBOOL is_busy; //线程状态:真忙; FLASE闲
- pthread_cond_t thread_cond;
- pthread_mutex_t的thread_lock;
- tp_work * th_work;
- tp_work_desc * th_job;
- };
- //主线程池的结构
- 结构 tp_thread_pool_s {
- TPBOOL(* INIT)(tp_thread_pool * 本);
- 无效 (*关)(tp_thread_pool * 本);
- 无效 (* process_job)(tp_thread_pool * 此,tp_work *工人,tp_work_desc *工作);
- INT (* get_thread_by_id)(tp_thread_pool * 此, INT ID);
- TPBOOL(* add_thread)(tp_thread_pool * 本);
- TPBOOL(* delete_thread)(tp_thread_pool * 本);
- INT (* get_tp_status)(tp_thread_pool * 本);
- INT min_th_num; //最小线程池中的数量
- INT cur_th_num; 在游泳池//当前线程数
- INT max_th_num; 在游泳池//最大线程数
- pthread_mutex_t的tp_lock;
- 的pthread_t manage_thread_id; //处理线程ID NUM
- tp_thread_info *的thread_info; //工作线程的线程相关信息
- };
- tp_thread_pool * creat_thread_pool(INT MIN_NUM, INT MAX_NUM);
线程pool.c(实现文件):
- #包括“线程pool.h”
- 静态 无效 * tp_work_thread(无效 *的pthread);
- 静态 无效 * tp_manage_thread(无效 *的pthread);
- 静态 TPBOOL tp_init(tp_thread_pool * 本);
- 静态 无效 tp_close(tp_thread_pool * 本);
- 静态 无效 tp_process_job(tp_thread_pool * 此,tp_work *工人,tp_work_desc *工作);
- 静态 INT tp_get_thread_by_id(tp_thread_pool * 此, INT ID);
- 静态 TPBOOL tp_add_thread(tp_thread_pool * 本);
- 静态 TPBOOL tp_delete_thread(tp_thread_pool * 本);
- 静态 INT tp_get_tp_status(tp_thread_pool * 本);
- / **
- *用户界面。科瑞线程池。
- *对:
- *民:分线数在池中创建
- *回报:
- *线程池结构实例创建成功
- * /
- tp_thread_pool * creat_thread_pool(INT MIN_NUM, INT MAX_NUM){
- tp_thread_pool * 本;
- 该 =(tp_thread_pool *)的malloc(sizeof运算(tp_thread_pool));
- memset的(这个,0, sizeof运算(tp_thread_pool));
- //初始化成员函数ponter
- 这- >的init = tp_init;
- 这- >关闭= tp_close;
- 这- > process_job = tp_process_job;
- 这- > get_thread_by_id = tp_get_thread_by_id;
- 这- > add_thread = tp_add_thread;
- 这- > delete_thread = tp_delete_thread;
- 这- > get_tp_status = tp_get_tp_status;
- //初始化成员变种
- 这- > min_th_num = MIN_NUM;
- 这- > cur_th_num = 本- > min_th_num;
- 这- > max_th_num = MAX_NUM;
- pthread_mutex_init(本- > tp_lock,NULL);
- // malloc的纪念品货号线程信息结构
- 如果(NULL =! 这- >的thread_info)
- 免费(本- >的thread_info);
- 这- >的thread_info =(tp_thread_info *)的malloc(sizeof运算(tp_thread_info)* 本- > max_th_num);
- 返回 此;
- }
- / **
- *成员函数的现实。线程池的初始化函数。
- *对:
- *这样的:线程池结构实例ponter
- *回报:
- *真:成功; 假:失败
- * /
- TPBOOL tp_init(tp_thread_pool * 本){
- 诠释 我;
- INT ERR;
- //科瑞工作线程并初始化工作线程信息
- 对于(i = 0;我< 本- > min_th_num;我++){
- pthread_cond_init(这- >的thread_info [i]于.thread_cond,NULL);
- pthread_mutex_init(&本- >的thread_info [i]于.thread_lock,NULL);
- ERR =的pthread_create(本- >的thread_info [I] .thread_id,NULL,tp_work_thread, 此);
- 如果(0!= ERR){
- 的printf(“tp_init:科瑞工作线程失败\ N” );
- 返回 FALSE;
- }
- 的printf(“tp_init:科瑞工作线程%D \ N” , 这- >的thread_info [I] .thread_id);
- }
- //科瑞管理线程
- ERR =的pthread_create(本- > manage_thread_id,NULL,tp_manage_thread, 此);
- 如果(0!= ERR){
- 的printf(“tp_init:科瑞管理线程失败\ N” );
- 返回 FALSE;
- }
- 的printf(“tp_init:科瑞管理线程%D \ N” , 这- > manage_thread_id);
- 返回 TRUE;
- }
- / **
- *成员函数的现实。线程池完全关闭功能。
- *对:
- *这样的:线程池结构实例ponter
- *回报:
- * /
- 无效 tp_close(tp_thread_pool * 本){
- 诠释 我;
- //关闭工作线程
- 对于(i = 0; I < 本- > cur_th_num;我++){
- 杀了(这个- >的thread_info [I] .thread_id,SIGKILL);
- pthread_mutex_destroy(本- >的thread_info [I] .thread_lock);
- pthread_cond_destroy(本- >的thread_info [I] .thread_cond);
- 的printf(“tp_close:杀工作线程%D \ N” , 这- >的thread_info [I] .thread_id);
- }
- //关闭线程管理
- 杀了(这个- > manage_thread_id,SIGKILL);
- pthread_mutex_destroy(本- > tp_lock);
- 的printf(“tp_close:杀了管理线程%D \ N” , 这- > manage_thread_id);
- //空闲线程结构
- 免费(本- >的thread_info);
- }
- / **
- *成员函数的现实。主界面打开。
- *让自己的工作和工作后,用户可以使用该功能来处理任务。
- *对:
- *这样的:线程池结构实例ponter
- *工作人员:用户任务的现实。
- *工作:用户对任务
- *回报:
- * /
- 无效 tp_process_job(tp_thread_pool * 此,tp_work *工人,tp_work_desc *作业){
- 诠释 我;
- INT tmpid;
- //填补这个 - >的thread_info的相关工作重点
- 对于(i = 0; I < 本- > cur_th_num;我++){
- 调用pthread_mutex_lock(本- >的thread_info [I] .thread_lock);
- 如果(!这- >的thread_info [I] .is_busy){
- 的printf(“tp_process_job:%D线空闲,线程ID为%d \ N” ,我, 这- >的thread_info [I] .thread_id);
- //线程状态设置忙碌的工作之前,
- 这- >的thread_info [I] .is_busy = TRUE;
- 调用pthread_mutex_unlock(本- >的thread_info [I] .thread_lock);
- 这- >的thread_info [I] .th_work =工作者;
- 这- >的thread_info [I] .th_job =工作;
- 的printf(“tp_process_job:通知空闲的工作线程%D,线程ID为%d \ N” ,我, 这- >的thread_info [I] .thread_id);
- 调用pthread_cond_signal(本- >的thread_info [I] .thread_cond);
- 返回;
- }
- 其他
- 调用pthread_mutex_unlock(本- >的thread_info [I] .thread_lock);
- } 的//结束
- //如果目前所有的线程都很忙,新的线程被创建在这里
- 调用pthread_mutex_lock(本- > tp_lock);
- 如果( 本- > add_thread(本)){
- I = 这个- > cur_th_num - 1;
- tmpid = 本- >的thread_info [I] .thread_id;
- 这- >的thread_info [I] .th_work =工作者;
- 这- >的thread_info [I] .th_job =工作;
- }
- 调用pthread_mutex_unlock(本- > tp_lock);
- //发送COND工作线程
- 的printf(“tp_process_job:通知空闲的工作线程%D,线程ID为%d \ N” ,我, 这- >的thread_info [I] .thread_id);
- 调用pthread_cond_signal(本- >的thread_info [I] .thread_cond);
- 返回;
- }
- / **
- *成员函数的现实。获得通过线程ID NUM真正的线程。
- *对:
- *这样的:线程池结构实例ponter
- * ID:线程ID NUM
- *回报:
- *在线程信息结构体数组序列NUM
- * /
- INT tp_get_thread_by_id(tp_thread_pool * 此, INT ID){
- 诠释 我;
- 对于(i = 0; I < 本- > cur_th_num;我++){
- 如果(ID == 本- >的thread_info [I] .thread_id)
- 回报 我;
- }
- 返回 -1;
- }
- / **
- *成员函数的现实。添加新线程入池。
- *对:
- *这样的:线程池结构实例ponter
- *回报:
- *真:成功; 假:失败
- * /
- 静态 TPBOOL tp_add_thread(tp_thread_pool * 本){
- INT ERR;
- tp_thread_info * new_thread;
- 如果( 本- > max_th_num <= 这个- > cur_th_num)
- 返回 FALSE;
- // malloc的新的线程信息结构
- new_thread = 本- >的thread_info [ 本- > cur_th_num]
- //初始化新线程的COND与互斥
- pthread_cond_init(new_thread-> thread_cond,NULL);
- pthread_mutex_init(new_thread-> thread_lock,NULL);
- //初始化状态为忙
- new_thread-> is_busy = TRUE;
- //在池中添加当前线程数。
- 这- > cur_th_num ++;
- ERR =的pthread_create(new_thread->的thread_id,NULL,tp_work_thread, 此);
- 如果(0!= ERR){
- 免费(new_thread);
- 返回 FALSE;
- }
- 的printf(“tp_add_thread:科瑞工作线程%D \ N” , 这- >的thread_info [ 本- > cur_th_num-1] .thread_id);
- 返回 TRUE;
- }
- / **
- *成员函数的现实。删除空闲线程池中。
- *只删除最后一个空闲线程池中。
- *对:
- *这样的:线程池结构实例ponter
- *回报:
- *真:成功; 假:失败
- * /
- 静态 TPBOOL tp_delete_thread(tp_thread_pool * 本){
- //当前线程NUM不能<分钟线NUM
- 如果(本- > cur_th_num <= 这个- > min_th_num) 返回 FALSE;
- //如果最后一个线程是忙,什么也不做
- 如果(本- >的thread_info [ 本- > cur_th_num-1] .is_busy) 返回 FALSE;
- //杀空闲线程和免费信息结构
- 杀了(这个- >的thread_info [ 本- > cur_th_num-1] .thread_id,SIGKILL);
- pthread_mutex_destroy(本- >的thread_info [ 本- > cur_th_num-1] .thread_lock);
- pthread_cond_destroy(本- >的thread_info [ 本- > cur_th_num-1] .thread_cond);
- //删除空闲线程后,当前线程NUM -1
- 这- > cur_th_num--;
- 返回 TRUE;
- }
- / **
- *成员函数的现实。获取当前线程池的状态:空闲的,正常的,忙碌的,.etc。
- *对:
- *这样的:线程池结构实例ponter
- *回报:
- * 0:空闲; 1:正常或占线(不处理)
- * /
- 静态 INT tp_get_tp_status(tp_thread_pool * 本){
- 浮 busy_num = 0.0;
- 诠释 我;
- //忙碌的线程数
- 对于(i = 0; I < 本- > cur_th_num;我++){
- 如果(本- >的thread_info [I] .is_busy)
- busy_num ++;
- }
- //0.2?或其他NUM?
- 如果(busy_num /(本- > cur_th_num)<BUSY_THRESHOLD)
- 返回 0; //空闲状态
- 其他
- 返回 1; //忙或正常状态
- }
- / **
- *内部接口。真正的工作线程。
- *对:
- * pthread的:线程池结构ponter
- *回报:
- * /
- 静态 无效 * tp_work_thread(无效 *的pthread){
- 的pthread_t curid; //当前线程的id
- INT NSEQ; //在这- >的thread_info数组当前线程的序列
- tp_thread_pool * 本 =(tp_thread_pool *)的pthread; //主线程池的结构实例
- //获取当前线程的id
- curid = pthread_self();
- //获取线程信息结构体数组中当前线程的序列。
- NSEQ = 本- > get_thread_by_id(本,curid);
- 如果(NSEQ <0)
- 返回;
- 的printf( “ 进入工作线程%D,线程ID为%d \ N” ,NSEQ,curid);
- //等待COND处理真正的工作。
- 而(TRUE){
- 调用pthread_mutex_lock(本- >的thread_info [NSEQ] .thread_lock);
- 调用pthread_cond_wait(本- >的thread_info [NSEQ] .thread_cond,与此- >的thread_info [NSEQ] .thread_lock);
- 调用pthread_mutex_unlock(本- >的thread_info [NSEQ] .thread_lock);
- 的printf( “%d 个线程做的工作\ñ!” ,pthread_self());
- tp_work * =工作 这个- >的thread_info [NSEQ] .th_work;
- tp_work_desc * =作业 本- >的thread_info [NSEQ] .th_job;
- //过程
- 与工作> process_job(工作职位);
- //线程状态设置下班后的空闲
- 调用pthread_mutex_lock(本- >的thread_info [NSEQ] .thread_lock);
- 这- >的thread_info [NSEQ] .is_busy = FALSE;
- 调用pthread_mutex_unlock(本- >的thread_info [NSEQ] .thread_lock);
- 的printf( “%d 执行工作在\ N” ,pthread_self());
- }
- }
- / **
- *内部接口。管理线程池来删除空闲线程。
- *对:
- * pthread的:线程池结构ponter
- *回报:
- * /
- 静态 无效 * tp_manage_thread(无效 *的pthread){
- tp_thread_pool * 本 =(tp_thread_pool *)的pthread; //主线程池的结构实例
- // 1?
- 睡眠(MANAGE_INTERVAL);
- 做{
- 如果( 本- > get_tp_status(本)== 0){
- 做{
- 如果(!这- > delete_thread(本))
- 打破;
- } 而(TRUE);
- } //结束,如果
- // 1?
- 睡眠(MANAGE_INTERVAL);
- } 而(TRUE);
- }
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。
性能低下。
连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器地服务效率,能够支持更多的客户服务。通过使用连接池,将大大提高程序运行效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
1)最小连接数是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;
2)最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。
参考资料:
1. libthreadpool库的实现:
2。 http://www.cnblogs.com/cute/archive/2012/09/18/2690616.html
3.“线程池技术在并发服务器中的应用” - 计算机与数字工程