基于0基础的线程池优化,这里最基本的问题是解决线程id的管理问题,以及线程取消的管理
这里採用链表来管理线程id,链表的特性便于新增和删除。引进thread_revoke结构体来标记全局的取消线程信息,先分析一下线程什么时候须要取消:当任务非常少,少到tasknum <threadnum* THREAD_WORKER_LOW_RATIO 时。也就是,任务的添加速度远远赶不上线程的处理速度时,会导致一部分线程处于饥饿状态(堵塞)。那么我们须要取消的就是处于饥饿状态的线程。
对于poisx多线程编程中线程的取消,一般採用pthread_cancel()并且此函数是无堵塞返回的(即不等线程是否真的取消)并且,这里有一个非常大非常大的疑惑,在线程取消的时候,线程必须等到在取消运行点处取消,这里我们的取消运行点是pthread_cond_wait()这线程处理堵塞状态,相互排斥锁在线程插入堵塞等待队列时已经释放掉。可是,线程本身处于堵塞状态下(放弃了时间片)会运行取消动作吗?我试验了一下。没有……
这里维护一个取消队列。在线程取消时。置全局取消标志位为1,pthread_broadcast()唤醒全部线程,让在线程唤醒时会推断是否进入取消状态,假设是直接主动退出。
当然这里有一个取消计数。
在我写的线程池中,实现了对线程的自己主动管理,依据任务的多少,自己主动添加线程或者删除线程,来保持资源的利用率。
my_thread_pool.h
#ifndef _MY_THREADPOOL_HEAD_ #define _MY_THREADPOOL_HEAD_ #include<stdio.h> #include<pthread.h> #include<unistd.h> #include<stdlib.h> #include<assert.h> #include<sys/types.h> #define THREAD_MINNUM 2 #define THREAD_MAXNUM 20 #define THREAD_DEFAULT 2 #define MANAGE_ADJUST_INTERVAL 5 #define WORKER_THREAD_HIGH_RATIO 3 #define WORKER_THREAD_LOW_RATIO 1 #define BUFFSIZE 1024 //task in pthread pool typedef struct pthread_work //任务信息 { void* (*task)(void *); void* args; //任务所带參数(就是pthread_work_info) struct pthread_work* next; }pthread_work; typedef struct pthread_work_info //用于表示运行任务的信息 { pthread_t pid; //哪个线程正在运行该任务 int number; //用来表示这是第几个任务 }pthread_work_info; typedef struct pthread_info //线程信息(用于线程池中存储堵塞线程) { pthread_t pid; struct pthread_info* next; }pthread_info; typedef struct thread_pool { int thread_currnum; //线程池中线程的个数 int thread_blocknum; //线程池中堵塞的线程个数 int thread_work; // 线程池中堵塞的任务个数 pthread_mutex_t pool_lock; pthread_cond_t pool_cond; pthread_work* work_head; //堵塞任务的起始地址 pthread_info* pthread_head; //堵塞线程的头节点 int shutdown; pthread_t manager_thread; //监控线程 }thread_pool; typedef struct pthread_invoke { int flag; //是否要删除线程 int invoked; //已删除线程个数 int need_invoke; //须要删除线程个数 }pthread_invoke; pthread_invoke *invoke=NULL; thread_pool *pool=NULL; void init_pool(); void init_invoke(); void destroy_pool(); int add_work_pool(pthread_work* ); int add_pthread_pool(); int delete_thread_pool(); void* pthread_run(void *); void* manager_pthreadpool(void *); void* my_process(void *args); #endif
my_thread_pool.c实现
#include"my_thread_pool.h" #include<fcntl.h> #include<string.h> void init_pool() { //初始化线程池,创建默认个数的堵塞线程 pool=(thread_pool *)malloc(sizeof(thread_pool)); pthread_mutex_init(&pool->pool_lock,NULL); pthread_cond_init(&pool->pool_cond,NULL); pool->shutdown=0; pool->work_head=NULL; pool->thread_currnum=THREAD_DEFAULT; pool->thread_blocknum=THREAD_DEFAULT; pool->thread_work=0; int i=0; pthread_info *p,*q; for(i=0;i<THREAD_DEFAULT;i++) { if(pool->pthread_head==NULL) { pool->pthread_head=(pthread_info*)malloc(sizeof(pthread_info)); pool->pthread_head->next=NULL; p=pool->pthread_head; } else if(i==THREAD_DEFAULT-1) { q=(pthread_info*)malloc(sizeof(pthread_info)); q->next=NULL; p->next=q; } else { q=(pthread_info*)malloc(sizeof(pthread_info)); q->next=NULL; p->next=q; p=q; } } p=pool->pthread_head; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); for(i=0;i<THREAD_DEFAULT;i++) { pthread_create(&p->pid,NULL,pthread_run,(void*)0); p=p->next; } //manager thread number pthread_create(&pool->manager_thread,NULL,manager_pthreadpool,NULL); } void* pthread_run(void *args) { int flag=0; //创建线程有2种方式。刚開始创建的都是堵塞线程。当线程数量不够时,再添加的线程是都不是堵塞线程,可直接运行的 int flag_block=(int)args; //flag_block=0 represent it is blocked pthread_t pthread_id=pthread_self(); printf("thread %x start ",pthread_id); while(1) { pthread_mutex_lock(&pool->pool_lock); //printf("thread %x start ",pthread_id); while(flag_block==0&&pool->shutdown==0&&pool->work_head==NULL) { if(flag) printf("thread %x will waiting ",pthread_id); pthread_cond_wait(&pool->pool_cond,&pool->pool_lock); } if(pool->shutdown==1) { printf("thread %x will exit ",pthread_id); pthread_mutex_unlock(&pool->pool_lock); pthread_exit(NULL); } pthread_info* currnode=pool->pthread_head; pthread_info* prexnode=pool->pthread_head; // remove the thread from the block queue while(currnode!=NULL) { if(currnode->pid==pthread_id) break; prexnode=currnode; currnode=currnode->next; } if(currnode!=NULL) { if(currnode==pool->pthread_head) { pool->pthread_head=pool->pthread_head->next; free(prexnode); } else if(currnode->next==NULL) { prexnode->next=NULL; free(currnode); } else { prexnode->next=currnode->next; free(currnode); } } if(invoke->flag==1&&invoke->invoked<invoke->need_invoke) { printf("the pthread %x is useless ,will exit ",pthread_self()); //delete ptthread_id from queue invoke->invoked++; pool->thread_currnum--; pool->thread_blocknum--; pthread_mutex_unlock(&pool->pool_lock); pthread_exit(NULL); } assert(pool->work_head!=NULL); pthread_work* work=pool->work_head; pool->work_head=pool->work_head->next; ((pthread_work_info*)work->args)->pid=pthread_id; pool->thread_work--; if(flag_block==0) pool->thread_blocknum--; pthread_mutex_unlock(&pool->pool_lock); (*work->task)(work->args); flag=1; pthread_mutex_lock(&pool->pool_lock); //if there is no work ,then the thread will block ,put it into blockqueue if(pool->work_head==NULL) { flag_block=0; pthread_info* p=(pthread_info *)malloc(sizeof(pthread_info)); p->next=pool->pthread_head; p->pid=pthread_self(); pool->pthread_head=p; //input into blocknum ,then should add thread_blocknum pool->thread_blocknum++; } else //运行任务后。还有任务,故不堵塞线程 flag_block=1; pthread_mutex_unlock(&pool->pool_lock); } pthread_exit(NULL); } void destroy_pool() //释放资源 { if(pool==NULL) return ; pthread_mutex_lock(&pool->pool_lock); pool->shutdown=1; pthread_mutex_unlock(&pool->pool_lock); pthread_cond_broadcast(&pool->pool_cond); //wait all pthread free rescource sleep(5); //free rescource pthread_cond_destroy(&pool->pool_cond); pthread_mutex_destroy(&pool->pool_lock); pthread_work* p=pool->work_head; while(p!=NULL) { pool->work_head=pool->work_head->next; free(p); p=pool->work_head; } pthread_info* info=pool->pthread_head; while(info!=NULL) { pool->pthread_head=pool->pthread_head->next; free(info); info=pool->pthread_head; } free(pool); pool=NULL; return ; } void *my_process(void* args) { pthread_work_info *work_info =(pthread_work_info *)args; printf("%x thread is working task %d ",work_info->pid,work_info->number); sleep(1); return ; } int add_work_pool(pthread_work* work) { pthread_mutex_lock(&pool->pool_lock); pthread_work* p=pool->work_head; if(p==NULL) pool->work_head=work; else { while(p->next!=NULL) p=p->next; p->next=work; } pool->thread_work++; pthread_mutex_unlock(&pool->pool_lock); pthread_cond_signal(&pool->pool_cond); return 1; } int main() { init_pool(); init_invoke(); int i; pthread_work * p; for(i=0;i<40;i++) { if(i>=20) sleep(1); p=(pthread_work *)malloc(sizeof(pthread_work)); p->task=my_process; p->next=NULL; p->args=malloc(sizeof(pthread_work_info)); ((pthread_work_info *)p->args)->number=i; add_work_pool(p); //sleep(1); } sleep(15); //等待全部任务都运行完,然后在删除线程池 destroy_pool(); return 0; } //use for manager pthreadpool every 5 seconds void* manager_pthreadpool(void *args) { char buff[BUFFSIZE]; while(1) { sleep(5); pthread_mutex_lock(&pool->pool_lock); if(pool->shutdown==1) pthread_exit(NULL); printf("the work num is %d,the thread num: %d , the ratio is %lf,the block is %d ",pool->thread_work,pool->thread_currnum,(double)pool->thread_work/pool->thread_currnum,pool->thread_blocknum); //display all the block pid; pthread_info* p=pool->pthread_head; while(p!=NULL) { printf("%x thread is blocked ",p->pid); p=p->next; } if(pool->thread_work/pool->thread_currnum>WORKER_THREAD_HIGH_RATIO) { //you must add thread number to adjust to the work(beacuse work is too many) int add_number=(pool->thread_work-pool->thread_currnum*WORKER_THREAD_HIGH_RATIO)/WORKER_THREAD_HIGH_RATIO; int i,err; pthread_attr_t attr; err=pthread_attr_init(&attr); if(err!=0) printf("attr error "); err=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); for(i=1;i<=add_number;i++) { //这些凝视掉的语句是。由于再次创建的线程都不会是堵塞线程,全部不用放入队列 //pthread_info *p=(pthread_info *)malloc(sizeof(pthread_info)); //p->next=pool->pthread_head; //p->pid=(pthread_t)0; pthread_t pid; pthread_create(&pid,&attr,pthread_run,(void *)1); //pool->pthread_head=p; pool->thread_currnum++; printf("thread %x add into the pool ",pid); } pthread_mutex_unlock(&pool->pool_lock); //strcpy(buff,"you must add thread "); //int size=strlen(buff); //write_data("a.txt",buff,size); } else if(pool->thread_work/pool->thread_currnum<WORKER_THREAD_LOW_RATIO) { //you must decrease thread number to adjust to the work if(pool->thread_blocknum!=0&&pool->thread_currnum>THREAD_MINNUM) { invoke->flag=1; invoke->invoked=0; invoke->need_invoke=(pool->thread_currnum-pool->thread_blocknum>=THREAD_MINNUM)?pool->thread_blocknum:(pool->thread_currnum-THREAD_MINNUM); pthread_mutex_unlock(&pool->pool_lock); pthread_cond_broadcast(&pool->pool_cond); } pthread_mutex_unlock(&pool->pool_lock); } else pthread_mutex_unlock(&pool->pool_lock); } } //初始化删除线程标志 void init_invoke() { invoke=(pthread_invoke*)malloc(sizeof(pthread_invoke)); invoke->flag=0; invoke->invoked=0; invoke->need_invoke=0; }