一、线程池的简介
线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
二、为何引入线程池
传统多线程方案中我们采用的服务器模型则是一旦接受到请求之后,即创建一个新的线程,由该线程执行任务。任务执行完毕后,线程退出,这就“即时创建,即时销毁”的策略。尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器将处于
不停的创建线程,销毁线程的状态,这笔开销将是不可忽略的。目前的大多数网络服务器,包括Web服务器、Email服务器以及数据库服务器等都具有一个共同点,就是单位时间内必须处理数目巨大的连接请求,但处理时间却相对较短。
三、线程池的特点
- 经典生产者消费者模型
- 线程池中有若干等待的线程
- 线程池中的线程用于执行大量的相对短暂的任务
四、线程池的工作流程
五、线程池对象
typedef struct{
pthread_mutex_t pool_lock; //互斥锁
pthread_cond_t cond; //条件变量
worker * queuehead; //队列头
int cur_queue_cont; //当前队列中成员个数
pthread_t * pthread_num; //线程号
int max_thread; //创建的线程的个数
int shutdown; //线程停止标志
}pool;
``
typedef struct work{
void * (*process)(void * arg);
//执行任务的函数指针
void * args; //传递的参数
struct work * next; //指向队列的下一个成员
}worker;
六、线程条件变量
sudo apt-get install manpages-posix-dev
//安装man手册
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
**功能 :**初始化一个条件变量
**参数 :** @cond:条件变量
@attr:NULL(linux 线程中忽略),所以直接填NULL;
**返回值 :**函数成功返回0;任何其他返回值都表示错误
int pthread_cond_destroy(pthread_cond_t *cond);
**功能 :**销毁一个条件变量
**参数 :** @cond:条件变量
**返回值 :**函数成功返回0;任何其他返回值都表示错误
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
**功能**:wait on a condition 阻塞等待条件(让其阻塞休眠)
**参数**:@cond:条件变量
@mutex:线程互斥锁
**返回值**:函数成功返回0;任何其他返回值都表示错误
**深入解析:**
1、阻塞等待条件满足后被唤醒;
2、如果条件不满足,释放互斥锁 pthread_mutex_unlock(&mutex);
3、当被唤醒时,解除阻塞,重新去申请互斥锁,phtread_mutex_lock(&mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
**功能:**唤醒pthread_cond_wait阻塞的线程
**区别:**
pthread_cond_signal:唤醒条件变量上的一个线程
pthread_cond_broadcast:唤醒条件变量上所有的线程
七、线程池实例分析
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct work{
void * (*process)(void * arg);
void * args;
struct work * next;
}worker;
//线程池对象
typedef struct{
pthread_mutex_t pool_lock;//互斥锁
pthread_cond_t cond;//条件变量
worker * queuehead;//队列头
int cur_queue_cont;/当前队列中成员个数
pthread_t * pthread_num;//线程号
int max_thread;//创建的线程个数
int shutdown;//线程停止标志
}pool;
//定义一个自己的线程池mypool,指针类型,在下面申请内存
pool *mypool;
void * thread_routine(void *args)//5个线程都是这个线程体,将线程号通过参数传递过来
{
pthread_t *tid = (pthread_t *)args;//转换线程号,类型转换
printf("start thread id = %ld.\n",*tid);
while(1){
pthread_mutex_lock(&mypool->pool_lock);
if(mypool->cur_queue_cont == 0 && !mypool->shutdown)
{
pthread_cond_wait(&mypool->cond,&mypool->pool_lock);//5个线程创建后不能执行,都在这里阻塞
}
if(mypool->shutdown)
{
pthread_mutex_unlock(&mypool->pool_lock);
pthread_exit(NULL);
}
mypool->cur_queue_cont --;
worker * work = mypool->queuehead;
mypool->queuehead = work->next;
pthread_mutex_unlock(&mypool->pool_lock);
work->process((void *)work->args);
}
}
void * invok_process(void * arg)
{
sleep(2);
printf("this is thread invok %d affair.\n",*(int *)arg);
}
void create_poll(int num)
{
int i,ret;
mypool = (pool *)malloc(sizeof(*mypool));//给mypool分配内存
if(mypool == NULL)
{
printf("malloc pool memory is fail.\n");
return ;
}
pthread_mutex_init(&mypool->pool_lock,NULL);//初始化互斥锁
pthread_cond_init(&mypool->cond,NULL);//初始化条件变量
mypool->queuehead = NULL;//将队列清空,因为创建线程池的时候还没有客户请求,队列里面没内容
mypool->shutdown = 0;//表示线程的退出,当值为1的时候才表示退出,在创建的时候应置0
mypool->max_thread = num;//线程最大个数
mypool->pthread_num = (pthread_t *)malloc(num*sizeof(pthread_t));//分配存放5个线程号的内存
for(i=0; i<num; i++)
{
ret = pthread_create(&(mypool->pthread_num[i]),NULL,
thread_routine,(void *)&(mypool->pthread_num[i]));
if(ret != 0)
{
printf("create thread is fail.\n");
}
}
}
void add_work(void * (*process)(void *),void *args)
{
worker *work = (worker *)malloc(sizeof(worker));
work->process = process;
work->args = args;
work->next = NULL;
pthread_mutex_lock(&mypool->pool_lock);
worker * pwork = mypool->queuehead;
if(pwork != NULL)
{
while(pwork->next != NULL)
pwork = pwork->next;
pwork->next = work;
}
else
{
mypool->queuehead = work;
}
mypool->cur_queue_cont ++;
pthread_mutex_unlock(&mypool->pool_lock);
pthread_cond_signal(&mypool->cond);
}
void destory_pool()
{
int i;
mypool->shutdown = 1;
pthread_cond_broadcast(&mypool->cond);
for(i=0; i<mypool->max_thread; i++)
{
pthread_join(mypool->pthread_num[i],NULL);
}
free(mypool->pthread_num);
worker * tmp;
while(mypool->queuehead)
{
tmp = mypool->queuehead;
mypool->queuehead = mypool->queuehead->next;
free(tmp);
}
pthread_mutex_destroy(&mypool->pool_lock);
pthread_cond_destroy(&mypool->cond);
}
int main(int argc, const char *argv[])
{
int i,num[10];
//create thread poll
create_poll(5);//创建线程池内有五个线程
sleep(2);
//add work,模拟客户请求,客户请求是10个
for(i=0; i<10; i++)
{
num[i] = i;
add_work(invok_process,(void *)&num[i]);
}
sleep(3);
//destory
destory_pool();
free(mypool);
printf("free resource is ok.\n");
return 0;
}