Linux下简单实现的线程池
2018-03-04 21:54
363 查看
thread_pool.h /************************************************************************* > File Name: thrread_pool.h > Author: arrayli > Mail: 1374367549@qq.com > Created Time: 2018年03月04日 星期日 15时11分38秒 ************************************************************************/ #ifndef _THRREAD_POOL_H #define _THRREAD_POOL_H #include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> #include<errno.h> #include<string.h> #define DEFAULT_TIME 10 /* 10s 检测一次 */ #define MIN_WAIT_TASK_NUM 10 /* 如果 queue_size > MIN_WAIT_TASK_NUM 添加新的线程到线程池 */ #define DEFAULT_THREAD_VARY 10 /* 每次创建和销毁的线程个数 */ #define true 1 #define false 0 typedef struct { void*(*function)(void*); /* 函数指针,执行回调函数 */ void *arg; /* 上面函数的 参数 */ }threadpool_task_t; /* 各子线程任务结构体 */ /* 描述线程池相关信息 */ typedef struct threadpool_t { pthread_mutex_t lock; /* 用于锁住本结构体 */ pthread_mutex_t thread_counter; /* 记录忙状态线程个数的锁 ---- busy_thr_num */ pthread_cond_t queue_not_full; /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */ pthread_cond_t queue_not_empty; /* 任务队列里不为空,通知等待任务的线程 */ pthread_t *threads; /* 存放线程池中每个线程的 tid ,数组 */ pthread_t adjust_tid; /* 存放管理线程 tid */ threadpool_task_t *task_queue; /* 任务队列 */ int max_thr_num; /* 线程池最大线程数 */ int min_thr_num; /* 线程池最小线程数 */ int busy_thr_num; /* 忙状态线程个数 */ int live_thr_num; /* 当前存活线程个数 */ int wait_exit_thr_num; /* 要销毁的线程个数 */ int queue_front; /* task_queue 队头下标 */ int queue_rear; /* task_queue 队尾下标 */ int queue_size; /* task_queue 队中实际任务数 */ int queue_max_size; /* task_queue 队列可容纳任务数上限 */ int shutdown; /* 标志位 线程池使用状态 true 或 false */ }threadpool_t ; /* typedef struct threadpool_t threadpool_t; */ void *threadpool_create(int min_thr_num,int max_thr_num,int queue_max_size); void *threadpool_thread(void *arg); void *adjust_thread(void*arg); int threadpool_add(threadpool_t* pool,void*(*function)(void *arg),void *arg); int threadpool_free(threadpool_t *pool); int is_thread_alive(pthread_t tid); int threadpool_destroy(threadpool_t *pool); #endifthread_pool.c
/*************************************************************************
> File Name: thrread_pool.c
> Author: arrayli
> Mail: 1374367549@qq.com
> Created Time: 2018年03月04日 星期日 15时12分33秒
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include"thread_pool.h"
/* typedef struct threadpool_t threadpool_t; */
void *threadpool_create(int min_thr_num,int max_thr_num,int queue_max_size)
{
int i;
threadpool_t *pool = NULL;
do
{
/* 给线程池数据结构分配内存 空间,若分配内存失败,则跳出 do-while 循环 */
if( (pool = (threadpool_t*)malloc(sizeof(threadpool_t))) == NULL)
{
printf("malloc threadpool failed!\n");
break;
}
/* 给线程池数据结构初始化 */
pool->min_thr_num = min_thr_num;
pool->max_thr_num = max_thr_num;
pool->busy_thr_num = 0;
pool->live_thr_num = min_thr_num; /* 活着的线程数 初值 = min_thr_num */
pool->queue_size = 0; /* 有 0 个产品 */
pool->queue_max_size = queue_max_size;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->shutdown = false; /* 不关闭线程池 */
/* 根据最大线程上限数,给工作线程数组开辟空间,并清零 */
pool->threads = (pthread_t*)malloc(sizeof(pthread_t)*max_thr_num);
if(!pool->threads)
{
printf("malloc threads failed\n");
break;
}
/* 线程数组,清零 */
memset(pool->threads,0x00,sizeof(pool->threads)*max_thr_num);
/* 队列开辟空间 */
pool->task_queue = (threadpool_task_t*)malloc(sizeof(threadpool_task_t)*queue_max_size);
/* 如果队列开辟空间失败 */
if(!pool->task_queue)
{
printf("malloc task_queue failed!\n");
break;
}
/* 初始化互斥锁,条件变量 */
if(pthread_mutex_init(&pool->lock,NULL) != 0 ||
pthread_mutex_init(&pool->thread_counter,NULL) != 0 ||
pthread_cond_init(&pool->queue_not_empty,NULL) != 0 ||
pthread_cond_init(&pool->queue_not_full,NULL) != 0
)
{
printf("init lock or cond failed!\n");
break;
}
/* 启动 min_thr_num 个 工作线程 */
for( i = 0; i < min_thr_num; i++ )
{
pthread_create(&pool->threads[i],NULL,threadpool_thread,(void*)pool); /* pool 指向当前线程池 */
printf("start thread 0x%x...\n",(unsigned int)pool->threads[i]);
}
/* 启动管理者线程 */
pthread_create(&pool->adjust_tid,NULL,adjust_thread,(void*)pool);
return pool;
}while(0);
/* 前面调用代码失败 */
threadpool_free(pool);
return NULL;
}
/* 线程池中各个工作线程 */
void *threadpool_thread(void *threadpool)
{
threadpool_t *pool = (threadpool_t*)threadpool;
threadpool_task_t task;
while(true)
{
/* 刚创建出线程,等待队列里有任务,否则阻塞在等待队列有任务后再唤醒接收任务 */
pthread_mutex_lock(&pool->lock);
/* queue_size == 0 ,说明没有任务,调用 wait 阻塞在条件变量上,若有任务,则跳过 while */
while(pool->queue_size == 0 && ! pool->shutdown)
{
printf("thread 0x%x is waiting!\n",(unsigned int)pthread_self());
pthread_cond_wait(&pool->queue_not_empty,&pool->lock);
/* 清除指定数目的空闲线程,如果要结束的线程大于 0 ,结束线程 */
if(pool->wait_exit_thr_num > 0 )
{
pool->wait_exit_thr_num--;
/* 如果线程池里的线程数大于最小值时,可以结束当前线程 */
if(pool->live_thr_num > pool->min_thr_num)
{
printf("thread 0x%x exiting\n",(unsigned int)pthread_self());
pool->live_thr_num--;
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
}
}
}
/* 如果指定了 true ,要关闭线程池里面的每一个线程,自行退出处理 */
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->lock);
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL); /* 线程自行结束 */
}
/* 从任务队列里取出任务,是一个出对操作 */
task.function = pool->task_queue[pool->queue_front].function;
task.arg = pool->task_queue[pool->queue_front].arg;
pool->queue_front = (pool->queue_front+1) % pool->queue_max_size; /* 出对,模拟环形队列 */
pool->queue_size--;
/* 通知可以有新的任务添加进来 */
pthread_cond_broadcast(&pool->queue_not_full);
/* 任务取出后,立即将线程池锁释放 */
pthread_mutex_unlock(&pool->lock);
/* 执行任务 */
printf("thread 0x%x start working\n",(unsigned int)pthread_self());
pthread_mutex_lock(&(pool->thread_counter)); /* 忙状态线程变量锁 */
pool->busy_thr_num ++;
pthread_mute
4000
x_unlock(&(pool->thread_counter));
(*(task.function))(task.arg); /* 执行回调函数任务 */
/* 任务结束处理 */
printf("thread 0x%x end working\n",(unsigned int)pthread_self());
pthread_mutex_lock(&(pool->thread_counter)); /* 忙状态线程变量锁 */
pool->busy_thr_num --;
pthread_mutex_unlock(&(pool->thread_counter));
}
pthread_exit(NULL);
}
/* 管理线程 */
void *adjust_thread(void*threadpool)
{
int i;
threadpool_t *pool = (threadpool_t*) threadpool;
while(!pool->shutdown)
{
sleep(DEFAULT_TIME); /* 定时 线程池进行管理 */
pthread_mutex_lock(&pool->lock);
int queue_size = pool->queue_size; /* 关注 任务数 */
int live_thr_num = pool->live_thr_num; /* 存活 线程数 */
pthread_mutex_unlock(&pool->lock);
pthread_mutex_lock(&(pool->thread_counter));
int busy_thr_num = pool->busy_thr_num; /* 忙着线程数 */
pthread_mutex_unlock(&(pool->thread_counter));
/* 当任务数量增加时,创建新的线程算法:任务数量大于最小线程数量,且存活的线程数少于最大线程数时,如:30>=10 && 40< 100 */
if(pool->queue_size>pool->min_thr_num && pool->live_thr_num < pool->max_thr_num)
{
pthread_mutex_lock(&pool->lock);
int add = 0;
/* 一次增加 DEFAULT_THREAD_VARY 个线程 */
for(i=0; i<pool->max_thr_num && add<DEFAULT_THREAD_VARY && pool->live_thr_num < pool->max_thr_num; i++)
{
if(pool->threads[0] == 0 || !is_thread_alive(pool->threads[i]))
{
pthread_create(&pool->threads[i],NULL,threadpool_thread,(void*)pool); /* pool 指向当前线程池 */
add++;
pool->live_thr_num++;
}
}
pthread_mutex_unlock(&pool->lock);
}
/* 销毁多余的空闲线程算法: 忙线程 * 2 小于存活的线程数 且 存活的线程数大于最小线程数时 */
if((busy_thr_num*2 > live_thr_num) && (live_thr_num < pool->min_thr_num))
{
/* 一次销毁 DEFAULT_THREAD_VARY 个线程,随机 10个即可 */
pthread_mutex_lock(&pool->lock);
pool->wait_exit_thr_num = DEFAULT_THREAD_VARY; /* 要销毁的线程数设置为 10 */
pthread_mutex_unlock(&pool->lock);
for( i=0; i<DEFAULT_THREAD_VARY;i++ )
{
/* 通知空闲处的线程,它们自行终止 */
pthread_cond_broadcast(&(pool->queue_not_empty));
}
}
}
return NULL;
}
/* 向线程池中添加一个任务 */
int threadpool_add(threadpool_t* pool,void*(*function)(void *arg),void *arg)
{
pthread_mutex_lock(&pool->lock);
/* == 为真 ,队列已经满,调用 wait 阻塞 */
while((pool->queue_size == pool->queue_max_size) && !(pool->shutdown))
{
pthread_cond_wait(&(pool->queue_not_full),&pool->lock);
}
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->lock);
}
/* 清空 工作线程 调用的回调函数 的参数arg */
if (pool->task_queue[pool->queue_rear].arg != NULL) {
free(pool->task_queue[pool->queue_rear].arg);
pool->task_queue[pool->queue_rear].arg = NULL;
}
/*添加任务到任务队列里*/
pool->task_queue[pool->queue_rear].function = function;
pool->task_queue[pool->queue_rear].arg = arg;
pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size; /* 队尾指针移动,
模拟环形 */
pool->queue_size++;
/*添加完任务后,队列不为空,唤醒线程池中 等待处理任务的线程*/
pthread_cond_signal(&(pool->queue_not_empty));
pthread_mutex_unlock(&(pool->lock));
}
int threadpool_free(threadpool_t *pool)
{
if(pool == NULL)
{
return -1;
}
if(pool->task_queue)
{
free(pool->task_queue);
}
if(pool->threads)
{
free(pool->threads);
pthread_mutex_lock(&pool->lock);
pthread_mutex_destroy(&pool->lock);
pthread_mutex_lock(&pool->thread_counter);
pthread_mutex_destroy(&pool->thread_counter);
pthread_cond_destroy(&pool->queue_not_empty);
pthread_cond_destroy(&pool->queue_not_full);
}
free(pool);
pool = NULL;
return 0;
}
int is_thread_alive(pthread_t tid)
{
int kill_rc = pthread_kill(tid,0); /* 发送 0 信号,测试信号是否存活 */
if(kill_rc == ESRCH)
{
return false;
}
return true;
}
int threadpool_destroy(threadpool_t *pool)
{
int i;
if( pool == NULL )
{
return -1;
}
pool->shutdown = true;
/* 先销毁管理者线程 */
pthread_join(pool->adjust_tid,NULL);
for( i=0;i<pool->live_thr_num;i++ )
{
/* 通知所有空闲线程 */
pthread_cond_broadcast(&pool->queue_not_empty);
}
for(i=0;i<pool->live_thr_num;i++)
{
pthread_join(pool->threads[i],NULL);
}
threadpool_free(pool);
return 0;
}
// 测试程序
/*************************************************************************
> File Name: main.c
> Author: arrayli
> Mail: 1374367549@qq.com
> Created Time: 2018年03月04日 星期日 20时33分26秒
************************************************************************/
#include<stdio.h>
#include"thread_pool.h"
void *process(void *arg)
{
printf("thread 0x%x working on task %d\n ",(unsigned int)pthread_self(),*(int *)arg);
sleep(1);
printf("task %d is end\n",*(int *)arg);
return NULL;
}
int main(void)
{
/* 创建线程池,池里最小 3 个线程,最大 100个,队列最大 100 */
threadpool_t * thp = threadpool_create(3,100,100);
printf("pool inited\n");
int num[20],i;
for(i=0;i<20;i++)
{
num[i] = i;
printf("add task %d\n",i);
threadpool_add(thp,process,(void*)&num[i]); /* 向线程池中添加任务 */
}
sleep(10); /* 等待子线程完成任务 */
threadpool_destroy(thp);
return 0;
}
相关文章推荐
- Linux 下C语言简单实现线程池
- 200行C代码实现简单线程池【Linux】
- 【收集】Linux线程池(C语言)及简单实现示例
- Linux 下C语言简单实现线程池
- Linux 下C语言简单实现线程池
- Linux下简单线程池的实现
- Linux 下C语言简单实现线程池
- linux下c/c++实例之十三C实现的简单的线程池
- LINUX C++ 线程池简单实现之双队列
- 【原创】TCP Socket 简单练习 --- 线程池实现并发服务器 分类: Linux --- 应用程序设计 2014-12-25 13:59 50人阅读 评论(0) 收藏
- Linux--线程池与进程池及线程池的简单实现
- 【转载】实现一个简单的linux线程池
- Linux下简单线程池的实现
- linux下C语言简单实现线程池
- Linux下一个简单线程池实现的源码注释
- Linux下简单线程池的实现
- Linux 下C语言简单实现线程池
- Linux下线程池的理解与简单实现
- linux下简单线程池实现
- 【收集】Linux线程池(C语言)及简单实现示例 分类: Linux --- 应用程序设计 2014-12-01 18:02 65人阅读 评论(0) 收藏