创建线程比起创建进程确实开销少了很多,若有大量任务,且执行时间都非常短暂,那么频繁创建新线程又很快销毁也十分影响性能。智慧的程序员们就想到了借助线程池来解决这样的问题。线程池中的一堆线程当有任务到来时就去执行,执行结束也不着急销毁,坐等下个任务的到来。这样就省下了一大笔创建销毁过程的开销
1.线程池中有若干个线程
2.用于执行大量相对短暂的任务
线程池中的线程个数如何确定?
- 对于计算密集型任务:线程池中线程个数=cpu个数
- 对应IO密集型任务:线程池线程个数小于cpu个数
当任务增加时,可动态增加线程池中线程个数
当任务执行完成后,可动态减少线程池中线程个数
本质上也是生产者消费者模型:生产者线程向任务队列中添加线程,任务队列中有任务,如果有等待线程就唤醒并执行任务,若线程池中没有等待线程且没有达到上限,就添加新的线程到线程池。
condition.h
#ifndef __CONDITION_H__
#define __CONDITION_H__
#include <pthread.h>
typedef struct condition
{
pthread_mutex_t pmutex;
pthread_cond_t pcond;
}condition_t;
void condition_init(condition_t *cond);
void condition_lock(condition_t *cond);
void condition_unlock(condition_t *cond);
void condition_wait(condition_t *cond);
int condition_timedwait(condition_t *cond,const struct timespec *abstime);
void condition_signal(condition_t *cond);
void condition_broadcast(condition_t *cond);
void condition_destroy(condition_t *cond);
#endif//__CONDITION_H__
condition.c
#include "condition.h"
void condition_init(condition_t *cond)
{
pthread_mutex_init(&cond->pmutex,NULL);
pthread_cond_init(&cond->pcond,NULL);
}
void condition_lock(condition_t *cond)
{
pthread_mutex_lock(&cond->pmutex);
}
void condition_unlock(condition_t *cond)
{
pthread_mutex_lock(&cond->pmutex);
}
void condition_wait(condition_t *cond)
{
pthread_cond_wait(&cond->pcond,&cond->pmutex);
}
int condition_timedwait(condition_t *cond,const struct timespec *abstime)
{
return pthread_cond_timedwait(&cond->pcond,&cond->pmutex,abstime);
}
void condition_signal(condition_t *cond)
{
pthread_cond_signal(&cond->pcond);
}
void condition_broadcast(condition_t *cond)
{
pthread_cond_broadcast(&cond->pcond);
}
void condition_destroy(condition_t *cond)
{
pthread_mutex_destroy(&cond->pmutex);
pthread_cond_destroy(&cond->pcond);
}
threadpool.h
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__
#include "condition.h"
typedef struct task
{
void *(*pfun)(void*);
void *arg;
struct task *next;
}task_t;
typedef struct threadpool
{
condition_t cond;
task_t *first;
task_t *tail;
int max_thread;
int idle;
int count;
int quit;
}threadpool_t;
void threadpool_init(threadpool_t* pool,int max);
void threadpool_add(threadpool_t* pool,void *(*pf)(void*),void* arg);
void threadpool_destroy(threadpool_t* pool);
#endif //__THREADPOOL_H__
threadpool.c
#include "threadpool.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void threadpool_init(threadpool_t* pool,int max)
{
condition_init(&pool->cond);
pool->first=pool->tail=NULL;
pool->max_thread=max;
pool->idle=0;
pool->count=0;
pool->quit=0;
}
void *route(void *arg)
{
threadpool_t *pool=(threadpool_t*)arg;
int timeout=0;
while(1)
{
condition_lock(&pool->cond);
pool->idle++;
while(pool->first==NULL&&pool->quit==0)
{
int ret=0;
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts);
ts.tv_sec+=2;
ret=condition_timedwait(&pool->cond,&ts);
if(ret == ETIMEDOUT)
{
timeout=1;
break;
}
}
pool->idle--;
if(pool->first!=NULL)
{
task_t *p=pool->first;
pool->first=p->next;
condition_unlock(&pool->cond);//too long
(p->pfun)(p->arg);
condition_lock(&pool->cond);
free(p);
}
if(pool->first==NULL&&timeout==1)
{
condition_unlock(&pool->cond);
printf("%#X thread timeout\n",pthread_self());
break;
}
if(pool->first==NULL&&pool->quit==1)
{
printf("%#X thread destroy\n",pthread_self());
pool->count--;
if(pool->count==0)
{
condition_signal(&pool->cond);
}
condition_unlock(&pool->cond);
break;
}
condition_unlock(&pool->cond);
}
}
void threadpool_add(threadpool_t* pool,void *(*pf)(void*),void *arg)
{
task_t *new=(task_t*)malloc(sizeof(task_t));
new->pfun=pf;
new->arg=arg;
new->next=NULL;
condition_lock(&pool->cond);
if(pool->first==NULL)
pool->first=new;
else
pool->tail->next=new;
pool->tail=new;
if(pool->idle > 0)
condition_signal(&pool->cond);
else if(pool->count < pool->max_thread)
{
pthread_t id;
pthread_create(&id,NULL,route,(void*)pool);
pool->count++;
}
condition_unlock(&pool->cond);
}
void threadpool_destroy(threadpool_t *pool)
{
if(pool->quit)
return;
condition_lock(&pool->cond);
pool->quit=1;
if(pool->count>0)
{
if(pool->idle>0)
condition_broadcast(&pool->cond);
}
while(pool->count>0)
condition_wait(&pool->cond);
condition_unlock(&pool->cond);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "threadpool.h"
void *myroute(void* arg)
{
int id=*(int *)arg;
free(arg);
printf("%#X thread running %d\n",pthread_self(),id);
sleep(1);
return NULL;
}
int main()
{
threadpool_t pool;
threadpool_init(&pool,3);
int i = 0;
for(i=0;i<10;i++)
{
int *p=(int*)malloc(sizeof(int));
*p=i;
threadpool_add(&pool,myroute,(void*)p);
}
threadpool_destroy(&pool);
//sleep(3);
}