一:线程池框架
1:在上一篇互斥锁文章中已经说过这个框架所以在这篇文章中就不多说了,但是上个版本实现的是简单的线程池并且存在效率问题,而且上个版本的互斥锁属性和线程属性为缺省属性,在这个版本中设置了相应的属性,接下来就说一下为什么存在效率问题为什么会设置属性。
(1)在上一个版本中保存请求任务的数据结构用的是c++标准库中的vector,而在将请求任务存入vector时存在数据的拷贝会消耗性能。线程在处理请求任务时将请求处理以后把请求任务从vector中删除因为每一次都删除的是vector中的第一个数据,如果有大量的请求保存在vector中那么每一次的删除都会存在数据的大量移动导致效率低下,针对这个问题解决办法是自己设计一个队列(链表形式)那么就会解决数据的移动问题,也不会存在数据的拷贝。
(2)线程属性的设置,在上个版本中没有设置相应的属性,而在这个版本中将线程的属性设置为PTHREAD_CREATE_DETACHED也就是线程分离状态。
int attr;
pthread_attr_t attr;
err=pthread_attr_init(&attr);
if(err!=0){
fprintf(stderr,"pthread_attr_init fail reason:%s\n",strerror(errno));
return NULL;
}
err=err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(err!=0){
fprintf(stderr,"pthread_attr_setdetachstate fail reason:%s\n",strerror(errno));
return NULL;
}
(3)什么是线程分离?为什么使用线程分离?
在创建线程的时候默认线程属性是joinable的也就是线程是非分离的,线程分离简单来说,就是将线程设置为unjoinable,如果不设置为线程分离那么线程在自己退出或调用pthread_exit()退出时就必须在主线程中调用pthread_join()函数来等待子线程的退出从而回收子线程的资源, 如果在主线程中不掉用pthread_jion()函数来回收子线程资源那么子线程就会成为”僵尸线程“,如果僵尸线程过多就会导致线程创建失败,如果在主线程中使用pthread_jion()函数来回收线程资源资源,如果子线程一直不退出那么pthread_join()将一直阻塞,而pthread_join()函数是在主线程中被调用,在主线程中还要处理其他任务,如果一直被阻塞那么就会导致其他任务无法处理,针对这几个问题解决办法就是将线程设置为分离状态,设置为分离状态以后就不用在主线程中调用pthread_jion()函数来回收线程资源,系统会自己回收线程资源。
(4)设置互斥锁属性,在上个版本中没有设置相应的属性,而在这个版本中将互斥锁的属性设置为PTHREAD_MUTEX_ERRORCHECK也就是检错锁,如果线程在不首先解除互斥锁的情况下尝试重新锁定该互斥锁,则返回错误,如果线程尝试解除的互斥锁已经由其他线程锁定,则返回错误,如果尝试解除的互斥锁未锁定,则返回错误,如果同一个线程请求同一个锁,则返回EDEADLK否则与这个PTHREAD_MUTEX_TIMED_NP属性动作相同保证了不会出现简单的死锁情况。
pthread_mutexattr_t attr;
err=pthread_mutexattr_init(&attr);
if(err!=0){
fprintf(stderr,"pthread_mutexattr_init fail reason%s\n",strerror(errno));
return ERROR;
}
err=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
if(err!=0){
fprintf(stderr,"pthread_mutexattr_settype fail reason:%s\n",strerror(errno));
return ERROR;
}
2:关键数据结构
struct thread_task_s{
thread_task_t *next;
uint_t id;
void *ctx;
void (*handle)(void *);
};
typedef struct{
thread_task_t *first;
thread_task_t **last;
}thread_pool_queue_t;
struct thread_pool_s{
pthread_mutex_t mutex;
pthread_cond_t cond;
thread_pool_queue_t queue;
char *name;
int_t waiting;
int_t max_queue;
uint_t threads;
};
3:线程池创建
thread_pool_t *thread_pool_create(){
pthread_attr_t attr;
thread_pool_t *tp=NULL;
int_t err;
pthread_t pid;
int_t n;
tp=calloc(1,sizeof(thread_pool_t));
if(!tp){
fprintf(stderr, "thread_pool_init: calloc failed!\n");
return NULL;
}
thread_pool_init_default(tp,NULL);
thread_pool_queue_init(&tp->queue);
err=thread_mutex_create(&tp->mutex);
if(err!=OK){
fprintf(stderr,"thread_pool_init: thread_mutex_create fail reason:%s\n",strerror(errno));
return NULL;
}
err=thread_cond_create(&tp->cond);
if(err!=OK){
fprintf(stderr,"thread_pool_init: thread_cond_create fail reason:%s\n",strerror(errno));
return NULL;
}
err=pthread_attr_init(&attr);
if(err!=0){
fprintf(stderr,"pthread_attr_init fail reason:%s\n",strerror(errno));
return NULL;
}
err=err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(err!=0){
fprintf(stderr,"pthread_attr_setdetachstate fail reason:%s\n",strerror(errno));
return NULL;
}
for(n=0;n<tp->threads;++n){
err=pthread_create(&pid,&attr,thread_pool_cycle,tp);
if(err!=0){
fprintf(stderr,"pthread_create fail reason:%s\n",strerror(errno));
free(tp);
return NULL;
}
}
(void) pthread_attr_destroy(&attr);
return tp;
}
4:任务队列的生成
int_t thread_task_post(thread_pool_t* tp,thread_task_t* task){
if(thread_mutex_lock(&tp->mutex)!=OK){
return ERROR;
}
tp->waiting++;
if(tp->waiting > tp->max_queue){
(void) thread_mutex_unlock(&tp->mutex);
fprintf(stderr,"thread pool \"%s\" queue overflow: %ld tasks waiting\n",
tp->name, tp->waiting);
return ERROR;
}
task->id=thread_pool_task_id++;
task->next=NULL;
*tp->queue.last=task;
tp->queue.last=&task->next;
tp->waiting++;
if (thread_cond_signal(&tp->cond) != OK) {
(void) thread_mutex_unlock(&tp->mutex);
return ERROR;
}
(void) thread_mutex_unlock(&tp->mutex);
if(debug)fprintf(stderr,"task #%lu added to thread pool \"%s\"\n",
task->id, tp->name);
return OK;
}
5:请求处理
static void *thread_pool_cycle(void *data){
thread_pool_t *tp=data;
thread_task_t *task;
int err;
while(1){
err=thread_mutex_lock(&tp->mutex);
if(err!=0){
return NULL;
}
tp->waiting--;
while(tp->queue.first==NULL){
err=thread_cond_wait(&tp->cond,&tp->mutex);
if(err!=OK){
(void) thread_mutex_unlock(&tp->mutex);
return NULL;
}
}
task=tp->queue.first;
tp->queue.first=task->next;
if(tp->queue.first==NULL){
tp->queue.last=&tp->queue.first;
}
err=thread_mutex_unlock(&tp->mutex);
if(err!=OK){
return NULL;
}
if(debug) fprintf(stderr,"run task #%lu in thread pool \"%s\"\n",
task->id, tp->name);
task->handle(task->ctx);
if(debug) fprintf(stderr,"complete task #%lu in thread pool \"%s\"\n",task->id, tp->name);
task->next = NULL;
free(task);
}
}
6:线程池销毁
void thread_pool_destroy(thread_pool_t* tp){
thread_task_t task;
int_t n;
volatile uint_t lock;
memset(&task,'\0',sizeof(task));
task.handle=thread_pool_exit_handler;
task.ctx=(void*)&lock;
for(n=0;n < tp->threads;++n){
lock=1;
if (thread_task_post(tp, &task) != OK) {
return;
}
while (lock) {
sched_yield();
}
}
(void)thread_mutex_destroy(&tp->mutex);
(void)thread_cond_destroy(&tp->cond);
}
给出部分函数,如果有需要源码,留言