1.为什么需要线程池?
一般情况下,我们在处理高并发的数据量的时候,对每一个用户创建一个线程用来处理,任务完成后,销毁线程。
假设时间开销 1.线程创建时间 2.线程执行时间 3.线程的销毁时间
2.线程池原理
线程池采用预创建的技术,在应用程序启动之后,立即创建一定数量的线程,放入空闲队列中,这些线程处于阻塞状态,不消耗CPU,只占用较小的内存。当创建的线程全部处于运行阶段,线程池将自动创建一定数量的线程放入线程池中用来处理更多的任务,当大部分线程处于暂停状态时,线程池自动销毁一部分线程,回收资源。
3.线程池框架
线程池:用于创建并管理线程
工作线程:线程池中实际执行的线程
任务接口:抽象线程执行的任务形成接口(执行函数及参数)
任务队列:实际实现中可能是一些常用的数据结构队列链表,保存线程
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
/*
线程池中任务队列的任务节点
*/
struct TaskNode
{
//线程处理任务时要执行的函数
void* (*func)(void* arg);
//执行任务时的参数
void* arg;
struct TaskNode* pre;//前驱节点
struct TaskNode* next;//后继节点
};
typedef struct TaskNode TaskNode;
struct ThreadPool
{
//线程同步机制
pthread_mutex_t mutex;
pthread_cond_t notify;
int close;//0表示不销毁 1表示销毁线程池
int run_num;//处于运行的线程的个数
int pthread_num;//线程创建的个数
pthread_t *pth;//线程数组的指针
int task_count;//节点(任务)的个数
int size;//最多的任务数量
TaskNode* head;//队列的头部
TaskNode* tail;//队列的尾部
};
typedef struct ThreadPool ThreadPool;
void* thread_task(void *threadpool)
{
ThreadPool *pool = (ThreadPool *)threadpool;
while(1)
{
pthread_mutex_lock(&pool->mutex);
//任务队列中没有任务时
while( 0 == pool->task_count && pool->close != 1 )
{
//等待任务
//当条件变量满足后会对信号量 再次加锁
pthread_cond_wait(&pool->notify, &pool->mutex);
}
//如果此时线程池要销毁了
if( 1 == pool->close )
{
pthread_mutex_unlock(&pool->mutex);
printf("pthread id is 0x%x exited\n", (unsigned int)pthread_self());
pthread_exit(NULL);
}
//获取要执行的具体任务并执行 temp用于释放头结点的空间以及具体的任务
TaskNode* temp;
temp = pool->head;
if(NULL == pool->head->next)
{
pool->head = pool->tail = NULL;
}
else
{
pool->head = pool->head->next;
if(NULL == pool->head)
{
pool->tail = pool->head;
pool->head->pre = NULL;
}
}
pool->task_count--;
pthread_mutex_unlock(&pool->mutex);
printf("start %d\n",*(int *)temp->arg);
//执行任务 函数指针
(*(temp->func))(temp->arg);
free(temp);
}
return NULL;
}
/*创建线程池
pthread_num 线程池中线程的个数
max_task_size 任务队列中最多的任务数量*/
ThreadPool* threadpool_create(int pthread_num, int max_task_size)
{
//迭代创建线程池中的线程的计数器
int i;
ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));
if(NULL == pool)
{
perror("malloc fail\n");
exit(-1);
}
//初始化操作
pool->close = 0;
pool->pthread_num = pthread_num;
pool->size = max_task_size;
pool->run_num = 0;
pool->pthread_num = 0;
pool->head = pool->tail = NULL;
pool->pth = NULL;
//对线程同步需要的信号量与条件进行初始化
if( 0 != pthread_mutex_init(&pool->mutex, NULL) || 0 != pthread_cond_init(&pool->notify, NULL) )
{
perror("pthread_init fail\n");
exit(-2);
}
//要创建的线程分配存储空间
pool->pth = (pthread_t*)malloc( sizeof(pthread_t) * pthread_num );
if( NULL == pool->pth )
{
perror("malloc fail\n");
exit(-1);
}
for(i=0; i<pthread_num; i++)
{
//pthread_thread 为线程执行的具体函数
//pool没有看完所有代码之前可能没有反应过来, 线程池中有需要执行的具体任务的参数 所以传递的为线程池指针,通过线程池指针, 在去获取具体执行的任务
pthread_create(&pool->pth[i], NULL, thread_task, (void*)pool);
printf("create pthread id 0x%x\n",(unsigned int)pool->pth[i]);
//此时才对相关的引用计数增加
pool->pthread_num++;
pool->run_num++;
}
return pool;
}
//向任务队列中添加任务
void add_task_threadpool(ThreadPool* pool, void* (*func)(void* arg), void* arg)
{
if(NULL == pool)
exit(0);
//任务队列已满
if(pool->task_count == pool->size)
{
perror("task too much\n");
sleep(5);
}
TaskNode *task = (TaskNode*)malloc(sizeof(TaskNode));
if(NULL == task)
{
perror("malloc fail\n");
exit(-1);
}
task->func = func;
task->arg = arg;
task->next = NULL;
task->pre = NULL;
//涉及到多个线程修改(添加 删除等方式)数据时一定要保证数据的同步
pthread_mutex_lock(&pool->mutex);
//队列为空
if(NULL == pool->head)
{
pool->head = task;
pool->tail = task;
}
else
{
pool->tail->next = task;
task->pre = pool->tail;
pool->tail = task;
}
pool->task_count++;
pthread_mutex_unlock(&pool->mutex);
//此时队列中有任务,唤醒线程池中的线程去处理任务
pthread_cond_signal(&pool->notify);
}
//线程池的销毁操作
void threadpool_destroy(ThreadPool* pool)
{
if(NULL == pool)
exit(0);
//已经调用过
if(1 == pool->close)
exit(0);
pool->close = 1;
int i;
//唤醒应条件变量阻塞的线程
pthread_cond_broadcast(&pool->notify);
//阻塞回收线程的资源
for(i=0; i<pool->pthread_num; i++)
pthread_join(pool->pth[i], NULL);
TaskNode *p = pool->head;
while(NULL != p)
{
pool->head = p->next;
p->next->pre = NULL;
free(p);
}
pthread_cond_destroy(&pool->notify);
pthread_mutex_destroy(&pool->mutex);
free(pool->pth);
free(pool);
pool->pth = NULL;
pool = NULL;
}
void* print(void* arg)
{
printf("pthread id %x\t%d\n",(unsigned int)pthread_self(), *(int*)arg);
}
int main()
{
int i=0;
ThreadPool *pool = threadpool_create(5, 1000);
printf("pthread num is %d\n",pool->pthread_num);
int* buf = (int*)malloc(sizeof(int) *500 );
while(i<500)
{
buf[i] = i;
add_task_threadpool(pool, print, (void*)&buf[i]);
printf("task num is %d\n",pool->task_count);
i++;
}
sleep(5);
threadpool_destroy(pool);
free(buf);
return 0;
}