备注:线程池学习时阅读的博客连接
初学线程池,在网上找了大量的文章,阅读参考后,以开头链接为模板自己写了一个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;
}
运行结果