c语言实现一个线程池——附程序demon,可编译执行

备注:线程池学习时阅读的博客连接
初学线程池,在网上找了大量的文章,阅读参考后,以开头链接为模板自己写了一个demon

一、线程池介绍
1.线程池的应用就是为了在需要大量线程创建、销毁时提高程序的执行效率而出现的
2.线程池重要的一个知识就是对队列的引用,通过读取队列的数据去执行队列中的任务,通过队列的数量判断是否需要创建、销毁线程!c语言创建队demon

二、线程池demon示例

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<signal.h>
#include<assert.h>
#include<string.h>
#include<errno.h>

#define MANAGER_THREAD_SLEEP  1 //工作线程工作时间间隔,多久工作一次
#define THREAD_WAIT_NUMBER 4 //新添加线程数,等待任务数大于工作线程数时新建线程
#define DESTORY_THREAD_NUMBER 4//销毁线程数,管理线程判断是否需要销毁线程


//队列的信息初始化
typedef struct{
	void *(*function)(void *);//线程执行的函数
	void *arg;//函数的参数
}thread_pool_msg;

//线程池信息结构体,存放了线程用到的信息
typedef struct {
	pthread_mutex_t lock_poo_t;  //对整个结构体上锁
	pthread_mutex_t work_num;   //操作工作线程数量时加的锁,便于读取,改变值时的精确性
	pthread_cond_t queue_not_full; //任务队列不为满,队列满添加线程睡眠
	pthread_cond_t  queue_not_empty;  //任务队列不为空,队列为空时,读取队列的线程睡眠

	pthread_t *threads; //相当于一个指针数组,存放线程的tid
	pthread_t manamger_tid; //管理线程的tid

	//队列信息结构
	int QUEUE_MAX_SIZE;//队列大小
	thread_pool_msg *pool_queue; //队列信息
	int queue_prev;
	int queue_next;
	int queue_szie;

	//线程池初始化信息
	int min_thread_num;  //线程池中最小存在的线程数
	int max_thread_num; //线程池中最多工作的线程数
	int live_thread_num; //线程池中存活的线程数量
	int work_thread_num; //线程池中正在工作的线程
	int leisure_thread_num; //空闲的线程数

	//线程池关闭标志
	int close; //等于1时关闭,0开启
}thread_pool_t;


//线程执行的函数
void *function(void *arg);

//*释放线程池
int thread_pool_free(thread_pool_t *pool);

//检测线程是否存活
int is_thread_alive(pthread_t tid);

//管理线程
void *manager_thread(void *threadpool);

//向线程池的任务队列中添加一个任务
int threadpool_add_task(thread_pool_t *pool, void *(*function)(void *arg), void *arg);

//工作线程运行的函数
void *threadpool_thread(void *threadpool);

//销毁线程池
int threadpool_destroy(thread_pool_t *pool);


/***********************
**1.创建线程池
************************/
thread_pool_t *create_thread_pool(int min_thread_num,int max_thread_num,int queue_max_size)
{
	int i;
	thread_pool_t *pool = NULL;

	do
	{
		pool=(thread_pool_t *)malloc(sizeof(thread_pool_t));//结构体初始化,分配空间
		if(NULL == pool)
		{
			printf("malloc fail\n");
			break;
		}

		pool->max_thread_num=max_thread_num;
		pool->min_thread_num=min_thread_num;
		pool->QUEUE_MAX_SIZE=queue_max_size;//队列大小
		pool->work_thread_num = 0;
		pool->live_thread_num = min_thread_num;
		pool->leisure_thread_num = 0;
		pool->queue_prev = 0;
		pool->queue_next = 0;
		pool->queue_szie = 0;
		pool->close = 0;

		//申请存放线程tid信息空间
		pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thread_num);
		if(NULL == pool->threads)
		{
			printf("malloc threads fail");
			break;
		}
		memset(pool->threads,0,sizeof(pthread_t)*max_thread_num);//将申请好的数组空间清0

		/*队列开空间*/
      pool->pool_queue = 
      ( thread_pool_msg*)malloc(sizeof(thread_pool_msg)*queue_max_size);
      if (pool->pool_queue == NULL)
      {
         printf("malloc task queue false;\n");
		 break;
      }

		//动态初始化互斥锁和条件变量
		if(pthread_mutex_init(&(pool->lock_poo_t), NULL) != 0           ||
		   pthread_mutex_init(&(pool->work_num), NULL) !=0  || 
	   	   pthread_cond_init(&(pool->queue_not_empty), NULL) !=0  ||
	       pthread_cond_init(&(pool->queue_not_full), NULL) !=0)
		{
			printf("init faile\n");
			break;
		}

		//创建最小存在数量个线程
		for(i=0;i<min_thread_num;i++)
		{
			pthread_create(&(pool->threads[i]),NULL,threadpool_thread,(void *)pool);
			//printf("the %x thread start work \n",(unsigned int)pool->threads[i]);
		}

		//创建管理者线程
		pthread_create(&(pool->manamger_tid), NULL, manager_thread, (void *)pool);
		return pool;
		
	}while(0);

	//释放pool申请的空间,避免内存泄漏
	thread_pool_free(pool);
	return NULL;
}

/***************
**释放线程池
****************/
int thread_pool_free(thread_pool_t *pool)
{
	if(pool == NULL)
	{
		return -1;
	}

	if(pool->pool_queue)
	{
		free(pool->pool_queue);
	}

	if(pool->threads)
	{

		free(pool->threads);
		pthread_mutex_lock(&(pool->lock_poo_t)); //上锁在销毁,确保销毁时锁处于打开状态
		pthread_mutex_destroy(&(pool->lock_poo_t));
		
		pthread_mutex_lock(&(pool->work_num));
		pthread_mutex_destroy(&(pool->work_num));

		pthread_cond_destroy(&(pool->queue_not_empty));
		pthread_cond_destroy(&(pool->queue_not_full));
	}
	free(pool);
	pool=NULL;

	return 0;
}

/***********
**销毁线程池
************/
int threadpool_destroy(thread_pool_t *pool)
{
	printf("开始清除线程池\n");
	int i;
	if(pool == NULL)
	{
		return -1;
	}

	pool->close=1;

	//回收线程资源
	pthread_join(pool->manamger_tid,NULL);

	for(i=0;i<pool->live_thread_num;i++)
	{
		pthread_cond_broadcast(&(pool->queue_not_empty));//唤醒所有阻塞的线程,自我判断退出
	}

	//等待线程结束,先pthread_exit 之后回收资源
	for(i=0;i<pool->live_thread_num;i++)
	{
		pthread_join(pool->threads[i],NULL);
	}
	thread_pool_free(pool);
	printf("销毁结束\n");
	return 0;
}



//工作线程运行的函数
void *threadpool_thread(void *threadpool)
{
	thread_pool_t *pool=(thread_pool_t *)threadpool;
	thread_pool_msg queue;

	while(1)
	{
		pthread_mutex_lock(&(pool->lock_poo_t));

		//队列大小为0时,创建的线程挂起,无任务执行
		while((pool->queue_szie == 0)&&(0==pool->close))
		{
			printf("线程 %x   挂起目前无任务执行 \n",(unsigned int)pthread_self());
			pthread_cond_wait(&(pool->queue_not_empty),&(pool->lock_poo_t));

			//如果任务队列中的任务为空,就去判断是否需要结束改线程
			if(pool->leisure_thread_num>0)
			{
				pool->leisure_thread_num--;
				if(pool->live_thread_num>pool->min_thread_num)
				{
					printf("thread %x is exiting \n",(unsigned int)pthread_self());
					pool->live_thread_num--;//存活线程数减1
					pthread_mutex_unlock(&(pool->lock_poo_t));
					pthread_exit(NULL);//结束线程
				}
			}
		}
		
		//判断线程池是否关闭,如果关闭,由线程池打开的线程自动销毁
		if(pool->close)
		{
			pthread_mutex_unlock(&(pool->lock_poo_t));
			printf("thread %x is exiting \n",(unsigned int)pthread_self());
			pthread_exit(NULL);
		}

		//如果不需要退出,就去读取任务队列的数据,执行相关函数
		queue.function=pool->pool_queue[pool->queue_prev].function;
		queue.arg=pool->pool_queue[pool->queue_prev].arg;

		pool->queue_prev=(pool->queue_prev+1)%pool->QUEUE_MAX_SIZE;//队列的首部进行移动
		pool->queue_szie--;//队列大小减1

		//通知等待入队列的数据,读取数据到队列
		pthread_cond_broadcast(&(pool->queue_not_full));

		pthread_mutex_unlock(&(pool->lock_poo_t));

		//执行刚才从队列中读取出来的数据
		//printf("the %x thread statr working \n",(unsigned int)pthread_self());
		pthread_mutex_lock(&(pool->work_num)); //上锁对工作线程数量统计
		pool->work_thread_num++;
		pthread_mutex_unlock(&(pool->work_num));

		//执行任务函数
		((*queue.function))(queue.arg);

		//printf("the thread %x woek end \n",(unsigned int)pthread_self());

		pthread_mutex_lock(&(pool->work_num)); //上锁对工作线程数量统计
		pool->work_thread_num--;
		pthread_mutex_unlock(&(pool->work_num));
	}
	pthread_exit(NULL);
}

/****************
**向队列中添加数据
*******************/
int threadpool_add_task(thread_pool_t *pool, void *(*function)(void *arg), void *arg)
{
	pthread_mutex_lock(&(pool->lock_poo_t));

//	printf("队列大小是 %d |队列最大为 %d | arg is %d\n",pool->queue_szie,pool->QUEUE_MAX_SIZE,arg);
	//如果队列满了,等待睡眠,等待队列有空间添加
	while((pool->queue_szie+1 == pool->QUEUE_MAX_SIZE) && (pool->close==0))
	{	
		printf("队列满 ===========\n");
		pthread_cond_wait(&(pool->queue_not_full),&(pool->lock_poo_t));
	}
	//如果线程池处于关闭状态,不添加
	if(pool->close==1)
	{
		pthread_mutex_unlock(&(pool->lock_poo_t));
		return -1;
	}
	
	//添加数据到任务队列
	pool->pool_queue[pool->queue_next].function=function;
	pool->pool_queue[pool->queue_next].arg=arg;
	pool->queue_next=(pool->queue_next+1)%(pool->QUEUE_MAX_SIZE);
	pool->queue_szie++;//队列大小加1
	//添加数据后,队列就不为空了,唤醒线程池中的一个线程*/
   pthread_cond_signal(&(pool->queue_not_empty));
   pthread_mutex_unlock(&(pool->lock_poo_t));
   return 0;
}

/*****************
**线程是否存活
******************/
int is_thread_alive(pthread_t tid)
{
   int kill_rc = pthread_kill(tid, 0);     //发送0号信号,测试是否存活
   if (kill_rc == ESRCH)  //线程不存在
   {
      return 0;
   }
   return 1;
}

/***************
**管理者线程函数
****************/
void *manager_thread(void *threadpool)
{
	int i;
	thread_pool_t *pool = (thread_pool_t *)threadpool;
	while(!pool->close)
	{
//		printf("manager thread start ==============\n");
		sleep(MANAGER_THREAD_SLEEP);
		
		pthread_mutex_lock(&(pool->lock_poo_t));
		int queue_size=pool->queue_szie; //队列大小,判定队列中存放等待执行的任务
		int live_thread_num=pool->live_thread_num; //存活的线程
		pthread_mutex_unlock(&(pool->lock_poo_t));
		
		pthread_mutex_lock(&(pool->work_num));
		int work_thread=pool->work_thread_num; //工作中的线程数
		pthread_mutex_unlock(&(pool->work_num));

		printf("==工作的线程有:%d         |  存活的线程有 :%d \n",work_thread,live_thread_num);

		//队列中的任务大于最小等待数时,就创建新的线程,并且存活的线程数小于最大存在线程数
		if(queue_size>=THREAD_WAIT_NUMBER && live_thread_num <=pool->max_thread_num)
		{
			printf("===add thread   ===\n");

			pthread_mutex_lock(&(pool->lock_poo_t));
			int add=0;

			//每次增加DESTORY_THREAD_NUMBER个线程
			for(i=0;i<pool->max_thread_num && add<DESTORY_THREAD_NUMBER
					&& pool->live_thread_num<pool->max_thread_num;i++)
			{
				if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i]))
				{
					pthread_create(&(pool->threads[i]),NULL,threadpool_thread,(void *)pool);
					add++;
					pool->live_thread_num++;
					printf("new thread add successful!=====\n");
				}
			}
			pthread_mutex_unlock(&(pool->lock_poo_t));
		}

		//销毁线程 如果工作的线程数*2的数量小于存活线程数,且存活线程数大于最小线程数
		if((work_thread*2)<live_thread_num && live_thread_num>pool->min_thread_num)
		{
			pthread_mutex_lock(&(pool->lock_poo_t));
			pool->leisure_thread_num = DESTORY_THREAD_NUMBER;
			pthread_mutex_unlock(&(pool->lock_poo_t));

			for(i=0;i<DESTORY_THREAD_NUMBER;i++)
			{
				pthread_cond_signal(&(pool->queue_not_empty));//通过唤醒线程,去让线程自己判断是否有事做,无事退出
				printf(" 管理线程 清除线程\n");
			}
		}

	}
	return NULL;
}

void *function(void *arg)
{
//	printf("线程 id   is %x   开始  ==============i is %d\n",pthread_self(),arg);
	sleep(2);
	printf("线程 id   is %x  工作结束===========is %d\n", (unsigned int)pthread_self(),arg);
	return 0;
}


int main()
{	
	int i=0;
	int min_thread_num=5;//最少存在5个线程
	int max_thread_num=10;//存在10个线程
	int queue_max_size=7;//队列最多存入6条任务
	thread_pool_t *pool = NULL;
	
	pool=create_thread_pool( min_thread_num, max_thread_num, queue_max_size);

	sleep(1);
	
	for(i=0;i<10;i++)
	{
	//	printf("====添加任务数量 %d \n",i);
		threadpool_add_task(pool, function, i);
	}

	sleep(5);
	threadpool_destroy(pool);//销毁线程池
	return 0;
}

运行结果
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值