zoukankan      html  css  js  c++  java
  • 线程池实现

    基于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;
    }
    


  • 相关阅读:
    缓存算法之LRU与LFU
    银行家算法
    死锁,死锁的四个必要条件以及处理策略
    找出无序数组中位数的方法
    HTTP状态码
    进程调度算法
    宽字节wchar_t和窄字节char的相互转换
    胜天半子
    ? 题目 一道超难的奥数题,猜生日. A告诉B他生日的月份,告诉C他生日的日期 B说:“如果我不知道A的生日,那C肯定也不知道." C说:”本来我不知道,现在我知道了.“ B说:”哦,那我也知道了.
    有对夫妇生有一男一女,一天晚上,成员中的一个杀了另一个,剩下2个成员,1个是帮凶1个是目击者
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7347174.html
Copyright © 2011-2022 走看看