线程池
池化技术:主要用于解决频繁的创建销毁操作带来的大量资源占用,顺带解决内存空间管理的问题
线程池实现思路:
1、需要有一个主线程处理请求
2、需要有一个管理线程处理任务队列和线程池的运行
3、线程池(任务队列空,线程池的线程等待,有任务时通知线程操作)
4、锁和条件变量(线程同步)
使用场景:
- 高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
- 并发不高、任务执行时间长的业务要区分开看:
- 假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务
- 假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
- 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦
用到的接口:
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
int pthread_join(pthread_t thread,
void **retval);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
typedef struct job//任务链结构
{
void *(*pthread_function)(void *arg);
void *arg;
struct job *next;
}job;
typedef struct pthread_pool//线程池结构
{
pthread_t *pthread_id;
pthread_t manage_id;
int pthread_num;
int pthread_max_num;
int pthread_min_num;
job *job_head;
job *job_tail;
int job_queue_num;
int job_queue_max_num;
pthread_mutex_t mutex;
pthread_cond_t job_queue_is_not_empty;
pthread_cond_t job_queue_is_not_full;
}pthread_pool;
//线程初始化后线程执行任务
void *pthread_handle(void *arg)
{
pthread_pool *pool = (pthread_pool *)arg;
while(1)
{
pthread_mutex_lock(&(pool->mutex));
while(pool->job_queue_num == 0)
{
pthread_cond_wait(&(pool->job_queue_is_not_empty), &(pool->mutex));
}
job *run_job;
run_job = pool->job_head;
printf("get function running\n");
pool->job_head = pool->job_head->next;
pool->job_queue_num--;
pthread_cond_broadcast(&(pool->job_queue_is_not_full));
pthread_mutex_unlock(&(pool->mutex));
pool->pthread_num++;
run_job->pthread_function(run_job->arg);
pool->pthread_num--;
free(run_job);
}
}
//管理线程执行的任务
void *pthread_pool_manage_handle(void *arg)
{
pthread_pool *pool = (pthread_pool *)arg;
while(1)
{
int i;
int count = 0;
sleep(5);//修改
pthread_mutex_lock(&(pool->mutex));
if((pool->job_queue_num > 10) && (pool->pthread_num < pool->pthread_max_num))
{
printf("-----------add pthread 5----------\n");
for(i = 0; (count < 5) && (pool->pthread_num < pool->pthread_max_num); i++)
{
if(pool->pthread_id[i] == 0)
{
pthread_create(&(pool->pthread_id[i]), NULL, pthread_handle, (void *)pool);
count++;
pool->pthread_min_num++;
}
}
}
printf("pthread_num = %d\n", pool->pthread_num);//测试
printf("pthread_min_num = %d\n", pool->pthread_num);
printf("job_queue_num = %d\n", pool->job_queue_num);
if((pool->pthread_num < 2) && (pool->pthread_min_num >= 2) && (pool->job_queue_num < 2))
{
printf("-------------sub pthread---------------");
pool->pthread_min_num = 2;
for(i = pool->pthread_max_num; i >= pool->pthread_max_num; i--)
{
pthread_join(pool->pthread_id[i], NULL);
}
}
pthread_mutex_unlock(&(pool->mutex));
}
}
int pthread_pool_add_job(pthread_pool *pool, void *(*function)(void *), void *arg)
{
pthread_mutex_lock(&(pool->mutex));//先上锁
while(pool->job_queue_num == pool->job_queue_max_num)
{
printf("job queue is full\n");
pthread_cond_wait(&(pool->job_queue_is_not_full), &(pool->mutex));
}
job *new_job = (job *)malloc(sizeof(job));
new_job->pthread_function = function;
new_job->arg = arg;
new_job->next = NULL;
if(pool->job_head == NULL)
{
pool->job_head = new_job;
pool->job_tail = new_job;
}
else
{
pool->job_tail->next = new_job;
pool->job_tail = pool->job_tail->next;
}
pool->job_queue_num++;
pthread_cond_broadcast(&(pool->job_queue_is_not_empty));
pthread_mutex_unlock(&(pool->mutex));//解锁
return 0;
}
//线程池初始化
pthread_pool *pthread_pool_init(int pthread_min_num, int pthread_max_num, int job_queue_max_num)
{
pthread_pool *pool;
pool = (pthread_pool *)malloc(sizeof(pthread_pool));
pool->pthread_min_num = pthread_min_num;
pool->pthread_max_num = pthread_max_num;
pool->pthread_id = (pthread_t *)malloc(sizeof(pthread_t) * pthread_max_num);
memset(pool->pthread_id, 0, sizeof(pthread_t) * pthread_max_num);
pool->job_head = NULL;
pool->job_tail = NULL;
pool->job_queue_num = 0;
pool->job_queue_max_num = job_queue_max_num;
if(pthread_mutex_init(&(pool->mutex), NULL) < 0)
{
printf("init mutex error\n");
exit(1);
}
if(pthread_cond_init(&(pool->job_queue_is_not_empty), NULL) < 0)
{
printf("init is not empty error\n");
exit(1);
}
if (pthread_cond_init(&(pool->job_queue_is_not_full), NULL) < 0)
{
printf("init is not full error\n");
exit(1);
}
for(int i = 0; i < pool->pthread_min_num; i++)
{
pthread_create(&(pool->pthread_id[i]), NULL, pthread_handle, (void *)pool);
}
pthread_create(&(pool->manage_id), NULL, pthread_pool_manage_handle, (void *)pool);
return pool;
}
int pthread_pool_destory(pthread_pool *pool)
{
int i;
for(i = 0; i < pool->pthread_num; i++)
{
printf("i = %d\n", i);
pthread_join(pool->pthread_id[i], NULL);
}
pthread_mutex_destroy(&(pool->mutex));
pthread_cond_destroy(&(pool->job_queue_is_not_full));
pthread_cond_destroy(&(pool->job_queue_is_not_empty));
printf("free pool\n");
free(pool->pthread_id);
free(pool);
return 0;
}
void *func(void *arg)
{
printf("thread func data = %s\n", (char *)arg);
sleep(4);//修改
}
int main()
{
pthread_pool *pool = pthread_pool_init(2, 100, 50);
pthread_pool_add_job(pool,func,"1");
pthread_pool_add_job(pool,func,"2");
pthread_pool_add_job(pool,func,"3");
pthread_pool_add_job(pool,func,"4");
pthread_pool_add_job(pool,func,"5");
pthread_pool_add_job(pool,func,"6");
pthread_pool_add_job(pool,func,"7");
pthread_pool_add_job(pool,func,"8");
pthread_pool_add_job(pool,func,"9");
pthread_pool_add_job(pool,func,"10");
pthread_pool_add_job(pool,func,"11");
pthread_pool_add_job(pool,func,"12");
pthread_pool_add_job(pool,func,"13");
pthread_pool_add_job(pool,func,"14");
pthread_pool_add_job(pool,func,"15");
pthread_pool_add_job(pool,func,"16");
pthread_pool_add_job(pool,func,"17");
pthread_pool_add_job(pool,func,"18");
pthread_pool_add_job(pool,func,"19");
pthread_pool_add_job(pool,func,"20");
pthread_pool_add_job(pool,func,"21");
pthread_pool_add_job(pool,func,"22");
pthread_pool_add_job(pool,func,"23");
pthread_pool_add_job(pool,func,"24");
pthread_pool_add_job(pool,func,"25");
pthread_pool_add_job(pool,func,"26");
pthread_pool_add_job(pool,func,"27");
pthread_pool_add_job(pool,func,"28");
pthread_pool_add_job(pool,func,"29");
pthread_pool_add_job(pool,func,"30");
sleep(1000);
pthread_pool_destory(pool);
return 0;
}