很多小伙伴们初学线程池的时候都很很迷茫,那么究竟什么是线程池呢?
其实线程池就是一个可容纳线程的容器,可以解决多任务高并发的无需多创建销毁。可以大大减小消耗CPU资源的一种解决方式。没有固定的实现方式。开发者可以根据自己的需求进行开发。
线程池的主要组成部分大概只有三个部分
1.执行对列 <==> 线程s
2.任务队列 <==> 任务s
3.管理组件
那线程池解决了什么问题?我大致归纳了4点
1.解决了任务处理
2.阻塞IO
3.解决线程创建与销毁成本
4.管理线程
废话不多说直接上代码
库文件
#include "pthread_pool.h"
#include <malloc.h>
#include <string.h>
#include <unistd.h>
//创建初始化线程池线程
PTHREADPOOL *init_pthreadPoolCreat(int minnum, int maxnum, int queueMaxSize)
{
PTHREADPOOL *pthreadPool = (PTHREADPOOL *)malloc(sizeof(PTHREADPOOL));
do
{
if (pthreadPool == NULL)
{
printf("创建失败\n");
break;
}
pthreadPool->thread_tID = (pthread_t *)malloc(sizeof(pthread_t) * maxnum);
if (pthreadPool->thread_tID == NULL)
{
printf("创建失败\n");
break;
}
//初始化申请的内存
//初始化为0用于后续的线程好存放判断使用
memset(pthreadPool->thread_tID, 0, sizeof(pthread_t) * maxnum);
//初始化线程池的信息
pthreadPool->minnum = minnum; //最小线程个数
pthreadPool->maxnum = maxnum; //最大线程个数
pthreadPool->busynum = 0; //忙碌线程
pthreadPool->livenum = minnum; //存活线程数量
pthreadPool->exitnum = 0; //销毁线程数量
//初始化锁
if (pthread_mutex_init(&pthreadPool->poolmutex, NULL) != 0 || pthread_mutex_init(&pthreadPool->busymutex, NULL) ||
pthread_cond_init(&pthreadPool->notfull, NULL) || pthread_cond_init(&pthreadPool->notempty, NULL))
{
printf("初始化失败\n");
break;
}
//任务队列初始化
pthreadPool->Qtask = (TASK *)malloc(sizeof(TASK) * queueMaxSize);
pthreadPool->queueFront = 0; //头
pthreadPool->queueSize = 0; //任务数量
pthreadPool->queueRear = 0; //尾
pthreadPool->shutdown = 0; //标识线程的状态
pthreadPool->queueMaxSize = queueMaxSize; //任务队列的数量
//创建管理者线程
pthreadPool->managerID = pthread_create(&pthreadPool->managerID, NULL, manager, pthreadPool);
if (pthreadPool->managerID != 0)
{
printf("创建管理者线程失败\n");
break;
}
int i = 0;
for (i = 0; i < minnum; i++)
{
if (pthread_create(&pthreadPool->thread_tID[i], NULL, myfunc, pthreadPool) != 0)
{
printf("创建线程失败[%d]\n", i);
break;
}
pthread_detach(pthreadPool->thread_tID[i]);
}
return pthreadPool;
} while (0);
//如何发生意外会跳出while循环开始释放资源
if (pthreadPool->thread_tID)
{
free(pthreadPool->thread_tID);
pthreadPool->thread_tID = NULL;
}
if (pthreadPool->Qtask)
{
free(pthreadPool->Qtask);
pthreadPool->Qtask = NULL;
}
if (pthreadPool)
{
free(pthreadPool);
pthreadPool = NULL;
}
return NULL;
}
//管理者线程函数
void *manager(void *arg)
{
//先将参数收一下
PTHREADPOOL *pool = (PTHREADPOOL *)arg;
int j = 0; //用以记录县城检测次数
int count = 1; //空闲销毁线程池使用
while (pool->shutdown == 0)
{
//每一秒检测一次
sleep(1);
pthread_mutex_lock(&pool->poolmutex); //因为在访问的时候要加锁
int queuesize = pool->queueSize;
int livenum = pool->livenum;
printf("管理者线程[%d]次检测,当前线程中任务队列个数为[%d],当前存活的线程个数为[%d]\n", j++, queuesize, livenum);
if (pool->queueSize == 0 && pool->livenum == 5)
{
printf("倒计时关闭[%d]线程池\n", count);
count--;
if (count == 0)
{
pthread_cond_signal(&pool->pooldestory); //关闭线程池
}
}
pthread_mutex_unlock(&pool->poolmutex);
pthread_mutex_lock(&pool->busymutex);
int busynum = pool->busynum;
printf("当前忙碌的线程为%d\n", busynum);
pthread_mutex_unlock(&pool->busymutex);
if ((queuesize > livenum) && (livenum < pool->maxnum))
{
printf("进入自动创建线程\n");
pthread_mutex_lock(&pool->poolmutex);
int counter = 0; //计数
int i = 0;
//判断条件循环不能大于线程的最大个数并且计数不能超过目标添加的个数并且存活的个数不能超过最大个数
for (i = 0; (i < pool->maxnum) && (counter < COUNT_NUM) && (livenum < pool->maxnum); i++)
{
if (pool->thread_tID[i] == 0)
{
pthread_create(&pool->thread_tID[i], NULL, myfunc, pool);
counter++;
pool->livenum++;
printf("自动创建线程成功\n");
pthread_detach(pool->thread_tID[i]);
}
}
pthread_mutex_unlock(&pool->poolmutex);
}
//销毁线程
if (busynum * 2 < livenum && livenum > pool->minnum)
{
pthread_mutex_lock(&pool->poolmutex);
pool->exitnum = COUNT_NUM; //每次销毁两个
pthread_mutex_unlock(&pool->poolmutex);
int i;
for (i = 0; i < COUNT_NUM; i++)
{
//工作线程会自动判断exitnum的大小如果唤醒后发现exit不为0就自动结束
pthread_cond_signal(&pool->notempty);
}
}
}
pthread_exit(NULL);
return NULL;
}
//执行函数
void *myfunc(void *arg)
{
PTHREADPOOL *pool = (PTHREADPOOL *)arg;
while (1)
{
pthread_mutex_lock(&pool->poolmutex); //操作线程池的临界资源就必须加锁
//当任务队列没有任务时工作线程成要阻塞等待人物的到来
while (pool->queueSize == 0 && !pool->shutdown) //判断线城池有没有关闭
{
pthread_cond_wait(&pool->notempty, &pool->poolmutex);
if (pool->exitnum > 0)
{
pool->exitnum--; //目标销毁的线程-1
pool->livenum--; //存活的线程-1
pthread_mutex_unlock(&pool->poolmutex); //解除锁
pthread_Exit(pool);
}
}
//唤醒后判断线程池是否关闭
if (pool->shutdown == 1)
{
pthread_mutex_unlock(&pool->poolmutex); //解除锁
pthread_Exit(pool); //关闭线程
}
//开始工作,从工作队列去除任务
TASK mytask;
mytask.fun = pool->Qtask[pool->queueFront].fun; //从头开始取任务
mytask.arg = pool->Qtask[pool->queueFront].arg; //从尾部取参数
//形成环队列
pool->queueFront = (pool->queueFront + 1) % pool->queueMaxSize;
pool->queueSize--;
//将移动后对队列尽行取于操作
pthread_cond_signal(&pool->notfull);
pthread_mutex_unlock(&pool->poolmutex);
//开始调用函数
//忙碌线程加一
pthread_mutex_lock(&pool->busymutex);
pool->busynum++; //忙碌线程+1
pthread_mutex_unlock(&pool->busymutex);
mytask.fun(mytask.arg); //开始工作
// //工作完成释放空间
// free(mytask.arg);
// mytask.arg=NULL;
printf("工作完成[%ld]\n", pthread_self());
//工作完成忙碌线程-1;
pthread_mutex_lock(&pool->busymutex);
pool->busynum--; //忙碌线程-1
pthread_mutex_unlock(&pool->busymutex);
}
return "线程执行完毕";
}
//给线程池添加任务函数
void ThreadPoolAdd(PTHREADPOOL *pool, void (*func)(void *), void *arg)
{
//判断任务队列是否满了
pthread_mutex_lock(&pool->poolmutex);
while (pool->queueSize == pool->queueMaxSize && !pool->shutdown)
{
//阻塞生产线线程
pthread_cond_wait(&pool->notfull, &pool->poolmutex);
//由工作线程拿走任务之后告知该线程
}
if (pool->shutdown)
{ //判断上个循环是否因为线程池销毁而退出循环
printf("线程池关闭,线程结束\n");
pthread_mutex_unlock(&pool->poolmutex);
return;
}
//添加任务到队尾
pool->Qtask[pool->queueRear].fun = func;
pool->Qtask[pool->queueRear].arg = arg;
//添加完任务,队列指针后移
pool->queueRear = (pool->queueRear + 1) % pool->queueMaxSize; //环形队列
pool->queueSize++; //任务队列加1
pthread_cond_signal(&pool->notempty); //唤醒消费者
pthread_mutex_unlock(&pool->poolmutex);
}
//退出线程函数
void pthread_Exit(PTHREADPOOL *pool)
{
pthread_t pid = pthread_self(); //获取当前线程号
int i;
for (i = 0; i < pool->maxnum; i++)
{
if (pid == pool->thread_tID[i])
{
pool->thread_tID[i] = 0;
printf("线程结束,该线程的线程号存放在数组的位置已经被清零\n");
break;
}
}
pthread_exit(NULL);
}
//获取忙碌线程的个数
int GetBusyNum(PTHREADPOOL *pool)
{
pthread_mutex_lock(&pool->busymutex);
int busynum = pool->busynum;
pthread_mutex_unlock(&pool->busymutex);
return busynum;
}
//获取可以工作的线程的个数
int GetLiveNum(PTHREADPOOL *pool)
{
pthread_mutex_lock(&pool->busymutex);
int livenum = pool->livenum;
pthread_mutex_unlock(&pool->busymutex);
return livenum;
}
//销毁线程池函数
int pthreadPoolDestory(PTHREADPOOL *pool)
{
pthread_mutex_lock(&pool->poolmutex);
//阻塞等待接收信号的到来
pthread_cond_wait(&pool->pooldestory, &pool->poolmutex);
pthread_mutex_unlock(&pool->poolmutex);
printf("开始释放资源\n");
if (pool == NULL)
{
return -1;
}
//关闭线程池
pool->shutdown = 1;
//销毁线程池
pthread_join(pool->managerID, NULL);
printf("结束原有的线程池的线程\n");
int i;
for (i = 0; i < pool->livenum; i++)
{
//将所有线程都唤醒后pool->sjout==1所以全部的线程都结束了
pthread_cond_signal(&pool->notempty);
}
//释放
pthread_mutex_destroy(&pool->poolmutex);
pthread_mutex_destroy(&pool->busymutex);
pthread_cond_destroy(&pool->notfull);
pthread_cond_destroy(&pool->notempty);
if (pool->thread_tID)
{
free(pool->thread_tID);
pool->thread_tID = NULL;
}
if (pool->Qtask)
{
free(pool->Qtask);
pool->Qtask = NULL;
}
if (pool)
{
free(pool);
pool = NULL;
}
}
头文件
#ifndef __PTHREAD_POOL_h__
#define __PTHREAD_POOL_H__
#include <pthread.h>
#define COUNT_NUM 2
//创建任务队列
typedef struct task
{
void (*fun)(void(*arg));
void *arg;
} TASK;
//创建线程池
typedef struct pthreadpool
{
TASK *Qtask; //任务队列数组
int queueMaxSize; //任务队列的容量
int queueSize; //当前任务队列的个数
int queueFront; //队头
int queueRear; //队尾
//线程池相关信息
pthread_t ID; //线程池ID
//工作线程ID
pthread_t *thread_tID; //因为多个所以直接使用一片地址
//管理者ID
pthread_t managerID;
//线程池的咸亨范围
int minnum; //最小的线程个数
int maxnum; //最大的线程个数
int busynum; //忙碌的线程个数
int livenum; //现在线程池可用的线程--存货的线程个数
int exitnum; //销毁线程的个数
//保护令临界资源
pthread_mutex_t poolmutex; //锁住线程池
pthread_mutex_t busymutex; //锁主busynum变量
//线程池同步唤醒机制--条件变量 来监视任务队列的状态
pthread_cond_t notfull; //判断任务队列是不是满了
pthread_cond_t notempty; //判断任务队列是不是空了
pthread_cond_t pooldestory; //判断工作空闲关闭判断条件变量
//线程池的状态1.运行 2.销毁
int shutdown; // 1.代表被销毁0.代表正在运行
} PTHREADPOOL;
//线程池初始化
PTHREADPOOL *init_pthreadPoolCreat(int minnum, int maxnum, int queueMaxSize);
//管理者线程函数
void *manager(void *arg);
//执行函数
void *myfunc(void *arg);
//给线程池添加任务函数
void ThreadPoolAdd(PTHREADPOOL *pool, void (*func)(void *), void *arg);
//退出线程函数
void pthread_Exit(PTHREADPOOL *pool);
//获取忙碌线程的个数
int GetBusyNum(PTHREADPOOL *pool);
//获取可以工作的线程的个数
int GetLiveNum(PTHREADPOOL *pool);
//销毁线程池函数
int pthreadPoolDestory(PTHREADPOOL *pool);
#endif
main文件
#include <stdio.h>
#include "pthread_pool.h"
#include <unistd.h>
#include <stdlib.h>
void func(void *arg)
{
int num = *(int *)arg;
printf("线程ID为%ld正在工作number=[%d]\n", pthread_self(), num);
sleep(3);
}
int main(int argc, char const *argv[])
{
//创建一个线程池
PTHREADPOOL *pool = init_pthreadPoolCreat(5, 200, 100);
if (pool == NULL)
{
printf("创建线程池失败\n");
return -1;
}
printf("创建线程池完毕\n");
//添加任务
int i;
for (i = 0; i < 200; i++)
{
int *num = (int *)malloc(4);
*num = i;
ThreadPoolAdd(pool, func, num);
}
pthreadPoolDestory(pool);
return 0;
}