目录
最后有全部代码,急需可以跳过
线程池是一种概念,用什么语言实现只是具体概念的一种表现,本质上还是一样的,只是实现细节不一样而已
线程池(thread pool)技术是指能够保证所创建的任一线程都处于繁忙状态,而不需要频繁地为了某一任务而创建和销毁线程,因为系统在创建和销毁线程时所耗费的cpu资源很大。如果任务很多,频率很高,为了单一一个任务而起线程而后销线程,那么这种情况效率相当低下的。线程池技术就是用于解决这样一种应用场景而应运而生的。
线程池技术的工作原理:在起先就创建一定数量的线程以队列形式存在,并为其分配一个工作队列,当工作队列为空时,表示没有任务,此时所有线程挂起等待新的工作到来。当新的工作到来时,线程队列头开始执行这个任务,然后依次是第二、第三个线程执行新到来的任务,当其中某个线程处理完任务后,那么该线程立马开始接受任务分派,从而让所有线程都处于忙碌的状态,提高并行处理效率。
在Unix网络编程中,线程与进程用于处理各项分支子功能,我们通常的操作是:接收消息 ==> 消息分类 ==> 线程创建 ==> 传递消息到子线程 ==> 线程分离 ==> 在子线程中执行任务 ==> 任务结束退出;
对大多数小型局域网的通信来说,上述方法足够满足需求;但当我们的通信范围扩大到广域网或大型局域网通信中时,我们将面临大量消息频繁请求服务器;在这种情况下,创建与销毁线程都已经成为一种奢侈的开销,特别对于嵌入式服务器来说更应保证内存资源的合理利用;
因此,线程池技术应运而生;线程池允许一个线程可以多次复用,且每次复用的线程内部的消息处理可以不相同,将创建与销毁的开销省去而不必来一个请求开一个线程;
结构讲解:
线程池是一个抽象的概念,其内部由任务队列,一堆线程,管理者线程组成;
我们将以上图为例,实现一个最基础的线程池,接下来将分部分依次讲解;讲解顺序为:1.线程池总体结构 2.线程数组 3.任务队列 4.管理者线程 5.使用线程池接口的例子
一、线程池总体结构
这里讲解线程池在逻辑上的结构体;看下方代码,该结构体threadpool_t中包含线程池状态信息,任务队列信息以及多线程操作中的互斥锁;在任务结构体中包含了一个可以放置多种不同任务函数的函数指针,一个传入该任务函数的void*类型的参数;
注意:在使用时需要将你的消息分类处理函数装入任务的(*function);然后放置到任务队列并通知空闲线程;
线程池状态信息:描述当前线程池的基本信息,如是否开启、最小线程数、最大线程数、存活线程数、忙线程数、待销毁线程数等… …
任务队列信息:描述当前任务队列基本信息,如最大任务数、队列不为满条件变量、队列不为空条件变量等… …
多线程互斥锁:保证在同一时间点上只有一个线程在任务队列中取任务并修改任务队列信息、修改线程池信息;
函数指针:在打包消息阶段,将分类后的消息处理函数放在(*function);
void*类型参数:用于传递消息处理函数需要的信息;
typedef struct Task
{
void (*function)(void * arg);
void * arg;
}Task;
// 线程池结构体
struct ThreadPool
{
// 任务队列
Task* taskQ;
int queueCapacity; // 容量
int queueSize; // 当前任务个数
int queueFront; // 队头 -> 取数据
int queueRear; // 队尾 -> 放数据
pthread_t managerID; // 管理者线程ID
pthread_t* threadIDs; // 工作的线程ID
int minNum; // 最小线程数量
int maxNum; // 最大线程数量
int busyNum; // 忙的线程的个数
int liveNum; // 存活的线程的个数
int exitNum; // 要销毁的线程个数
pthread_mutex_t mutexPool; // 锁整个的线程池
pthread_mutex_t mutexBusy; // 锁busyNum变量
pthread_cond_t notFull; // 任务队列是不是满了
pthread_cond_t notEmpty; // 任务队列是不是空了
int shutdown; // 是不是要销毁线程池, 销毁为1, 不销毁为0
};
/*
*threadPoolCreate:创建线程池并初始化
int min:直接可以用的工作线程数量
int max:最大工作的线程数量
int queueSize:创建任务队列的数量
返回值:创建并初始化的一个线程池
*/
ThreadPool* threadPoolCreate(int min, int max, int queueSize)
{
ThreadPool * pool = (ThreadPool *)malloc(sizeof(ThreadPool));
do
{
if(pool == NULL)
{
printf("malloc ThreadPool failed\n");
break;
}
pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t)*max);
if(pool->threadIDs == NULL)
{
printf("malloc threadIDs failed\n");
break;
}
//memset(pool->threadIDs,0,sizeof(pthread_t) * max);
for(int i = 0; i < max; i++)
{
pool->threadIDs[i] = 0;
printf("%ld\n",pool->threadIDs[i]);
}
pool->minNum = min;
pool->maxNum = max;
pool->busyNum = 0;
pool->liveNum = min;
pool->exitNum = 0;
if(pthread_mutex_init(&pool->mutexPool,NULL) != 0 ||
pthread_mutex_init(&pool->mutexBusy,NULL) != 0 ||
pthread_cond_init(&pool->notEmpty,NULL) != 0 ||
pthread_cond_init(&pool->notFull,NULL) != 0)
{
printf("mutex or cond init failed\n");
break;
}
//任务队列
pool->taskQ = (Task*)malloc(sizeof(Task) * queueSize);
pool->queueCapacity = queueSize;
pool->queueFront = 0;
pool->queueRear = 0;
pool->shutdown = 0;
//创建线程
error = pthread_create(&pool->managerID,NULL,manager,pool);
if(error != 0)
{
perror("create pthread_create managerID failed");
break;
}
for(int i = 0;i < min; i++)
{
pthread_create(&pool->threadIDs[i],NULL,worker,pool);
if(error != 0)
{
perror("create pthread_create threadIDs failed");
break;
}
}
return pool;
}while(0);
//初始化失败,释放资源
if(pool && pool->threadIDs) free(pool->threadIDs);
if(pool && pool->taskQ) free(pool->taskQ);
if(pool) free(pool);
return NULL;
}
二、线程数组
线程数组实际上是在线程池初始化时开辟的一段存放一堆线程tid的空间,在逻辑上形成一个池,里面放置着提前创建的线程;这段空间中包含了正在工作的线程,等待工作的线程(空闲线程),等待被销毁的线程,申明但没有初始化的线程空间;
// 工作的线程(消费者线程)任务函数
void* worker(void* arg)
{
ThreadPool * pool = (ThreadPool *) arg;
while(1)
{
pthread_mutex_lock(&pool->mutexPool);
//当前任务队列是否为空
while(pool->queueSize == 0 && !pool->shutdown)
{
//阻塞工作线程
pthread_cond_wait(&pool->notEmpty,&pool->mutexPool);
//判断是否用销毁线程
if(pool->exitNum > 0)
{
pool->exitNum--;
if(pool->liveNum > pool->minNum)
{
pool->liveNum--;
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
}
}
//判断线程池是否被关闭
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
//从任务队列中取出一个任务
Task task;
task.function = pool->taskQ[pool->queueFront].function;
task.arg = pool->taskQ[pool->queueFront].arg;
//移动头节点
pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
pool->queueSize--;
//解锁
pthread_cond_signal(&pool->notFull);
pthread_mutex_unlock(&pool->mutexPool);
printf("thread %ld start working...\n",pthread_self());
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum++;
pthread_mutex_unlock(&pool->mutexBusy);
//执行
task.function(task.arg);
free(task.arg);
task.arg = NULL;
printf("thread %ld end working...\n",pthread_self());
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum--;
pthread_mutex_unlock(&pool->mutexBusy);
}
return NULL;
}
三、添加任务队列
任务队列的存在形式与线程数组相似;在线程池初始化时根据传入的最大任务数开辟空间;当服务器前方后请求到来后,分类并打包消息成为任务,将任务放入任务队列并通知空闲线程来取;不同之处在于任务队列有明显的先后顺序,先进先出;而线程数组中的线程则是一个竞争关系去拿到互斥锁争取任务;
/*
*threadPoolAdd:给线程池添加任务
ThreadPool* pool:线程池
void(*func)(void*):要加到任务中的函数指针
void* arg:要加到任务中的函数指针的参数
返回值:无
*/
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg)
{
pthread_mutex_lock(&pool->mutexPool);
while(pool->queueSize == pool->queueCapacity && !pool->shutdown)
{
//因为任务队列满了或者线程池需要销毁,阻塞生产者线程
pthread_cond_wait(&pool->notFull, &pool->mutexPool);
}
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->mutexPool);
return ;
}
//添加任务
pool->taskQ[pool->queueRear].function = func;
pool->taskQ[pool->queueRear].arg = arg;
pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;
pool->queueSize++;
pthread_cond_signal(&pool->notEmpty);
pthread_mutex_unlock(&pool->mutexPool);
}
四、管理者线程
作为线程池的管理者,该线程的主要功能包括:检查线程池内线程的存活状态,工作状态;负责根据服务器当前的请求状态去动态的增加或删除线程,保证线程池中的线程数量维持在一个合理高效的平衡上;
说到底,它就是一个单独的线程,定时的去检查,根据我们的一个维持平衡算法去增删线程
// 管理者线程任务函数
void* manager(void* arg)
{
ThreadPool * pool = (ThreadPool *)arg;
while(!pool->shutdown)
{
//3s检查一次
sleep(3);
//取出线程池任务的数量和当前线程的数量
pthread_mutex_lock(&pool->mutexPool);
int queueSize = pool->queueSize;
int liveNum = pool->liveNum;
printf("liveNum = %d\n",liveNum);
pthread_mutex_unlock(&pool->mutexPool);
//取出忙的线程的数量
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
printf("busyNum = %d\n",busyNum);
pthread_mutex_unlock(&pool->mutexBusy);
//添加线程
//任务的个数 > 成活的线程个数 && 存活的线程数 < 最大线程数
if(queueSize > liveNum && liveNum < pool->maxNum)
{
pthread_mutex_lock(&pool->mutexPool);
for(int i = 0; i < pool->maxNum && pool->liveNum < pool->maxNum; i++)
{
if(pool->threadIDs[i] == 0)
{
pthread_create(&pool->threadIDs[i],NULL,worker,pool);
pool->liveNum++;
}
}
pthread_mutex_unlock(&pool->mutexPool);
}
//销毁线程
//条件是:忙的线程*2 < 存活的线程数 && 存活的线程 > 最小线程数
//我觉得,释放多余内存
if(busyNum * 2 < liveNum && liveNum > pool->minNum)
{
pthread_mutex_lock(&pool->mutexPool);
liveNum = pool->liveNum;
busyNum = pool->busyNum;
int NUMBER = liveNum-busyNum;
pool->exitNum = NUMBER;
pthread_mutex_unlock(&pool->mutexPool);
//发信号让线程自杀,具体实现就是每个线程的有一个销毁判断
//每次销毁一个,pool->exitNum--,直到为0
for(int i = 0 ;i < NUMBER; i++)
{
pthread_cond_signal(&pool->notEmpty);
}
}
}
return NULL;
}
五 、销毁
/*
*threadPoolDestroy:销毁线程池
ThreadPool* pool:需要销毁的线程池
返回值:失败返回 -1,成功返回 0;
*/
int threadPoolDestroy(ThreadPool* pool)
{
if(pool == NULL)
{
return -1;
}
//关闭线程池
pool->shutdown = -1;
//阻塞回收管理者线程
pthread_join(pool->managerID,NULL);
//唤醒阻塞的消费者线程 = 工作线程
for(int i = 0; i < pool->liveNum; i++)
{
pthread_cond_signal(&pool->notEmpty);
}
//释放堆内存
if(pool->taskQ)
{
free(pool->taskQ);
}
if(pool->threadIDs)
{
free(pool->threadIDs);
}
//销毁互斥量,条件变量
pthread_mutex_destroy(&pool->mutexPool);
pthread_mutex_destroy(&pool->mutexBusy);
pthread_cond_destroy(&pool->notEmpty);
pthread_cond_destroy(&pool->notFull);
free(pool);
pool = NULL;
return 0;
}
六 、其他子函数
/*
*threadExit:单个线程退出
ThreadPool* pool:需要退出的线程
*/
void threadExit(ThreadPool* pool)
{
pthread_t tid =pthread_self();
for(int i = 0; i < pool->maxNum; i++)
{
if(pool->threadIDs[i] == tid)
{
pool->threadIDs[i] = 0;
printf("threadExit() called, %ld exiting...\n",tid);
break;
}
}
pthread_exit(NULL);
return;
}
/*
*threadPoolBusyNum:获取线程池中工作的线程的个数
ThreadPool* pool:线程池
返回值:当前工作线程个数
*/
int threadPoolBusyNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
return busyNum;
}
/*
*threadPoolBusyNum:获取线程池中活着的线程的个数
ThreadPool* pool:线程池
返回值:当前活着的线程的个数
*/
int threadPoolAliveNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexPool);
int aliveNum = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
return aliveNum;
}
七 、测试代码
//测试案例
void taskFunc(void * arg)
{
int num = *(int *)arg;
printf("taskFunc thread %ld is working, number = %d\n",pthread_self(),num);
sleep(3);
}
int main()
{
//创建线程池
ThreadPool * pool = threadPoolCreate(5,15,100);
for(int i = 0; i < 100; i++)
{
int * num = (int *)malloc(sizeof(int));
*num = i+100;
threadPoolAdd(pool,taskFunc,num);
}
//主线程等待子线程完成
while(1);
sleep(30);
threadPoolDestroy(pool);
return 0;
}
附录(代码)
#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct Task
{
void (*function)(void * arg);
void * arg;
}Task;
// 线程池结构体
struct ThreadPool
{
// 任务队列
Task* taskQ;
int queueCapacity; // 容量
int queueSize; // 当前任务个数
int queueFront; // 队头 -> 取数据
int queueRear; // 队尾 -> 放数据
pthread_t managerID; // 管理者线程ID
pthread_t* threadIDs; // 工作的线程ID
int minNum; // 最小线程数量
int maxNum; // 最大线程数量
int busyNum; // 忙的线程的个数
int liveNum; // 存活的线程的个数
int exitNum; // 要销毁的线程个数
pthread_mutex_t mutexPool; // 锁整个的线程池
pthread_mutex_t mutexBusy; // 锁busyNum变量
pthread_cond_t notFull; // 任务队列是不是满了
pthread_cond_t notEmpty; // 任务队列是不是空了
int shutdown; // 是不是要销毁线程池, 销毁为1, 不销毁为0
};
typedef struct ThreadPool ThreadPool;
// 创建线程池并初始化
ThreadPool* threadPoolCreate(int min, int max, int queueSize);
// 销毁线程池
int threadPoolDestroy(ThreadPool* pool);
// 给线程池添加任务
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg);
// 获取线程池中工作的线程的个数
int threadPoolBusyNum(ThreadPool* pool);
// 获取线程池中活着的线程的个数
int threadPoolAliveNum(ThreadPool* pool);
// 工作的线程(消费者线程)任务函数
void* worker(void* arg);
// 管理者线程任务函数
void* manager(void* arg);
// 单个线程退出
void threadExit(ThreadPool* pool);
int error; //错误码
/*
*threadPoolCreate:创建线程池并初始化
int min:直接可以用的工作线程数量
int max:最大工作的线程数量
int queueSize:创建任务队列的数量
返回值:创建并初始化的一个线程池
*/
ThreadPool* threadPoolCreate(int min, int max, int queueSize)
{
ThreadPool * pool = (ThreadPool *)malloc(sizeof(ThreadPool));
do
{
if(pool == NULL)
{
printf("malloc ThreadPool failed\n");
break;
}
pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t)*max);
if(pool->threadIDs == NULL)
{
printf("malloc threadIDs failed\n");
break;
}
//memset(pool->threadIDs,0,sizeof(pthread_t) * max);
for(int i = 0; i < max; i++)
{
pool->threadIDs[i] = 0;
printf("%ld\n",pool->threadIDs[i]);
}
pool->minNum = min;
pool->maxNum = max;
pool->busyNum = 0;
pool->liveNum = min;
pool->exitNum = 0;
if(pthread_mutex_init(&pool->mutexPool,NULL) != 0 ||
pthread_mutex_init(&pool->mutexBusy,NULL) != 0 ||
pthread_cond_init(&pool->notEmpty,NULL) != 0 ||
pthread_cond_init(&pool->notFull,NULL) != 0)
{
printf("mutex or cond init failed\n");
break;
}
//任务队列
pool->taskQ = (Task*)malloc(sizeof(Task) * queueSize);
pool->queueCapacity = queueSize;
pool->queueFront = 0;
pool->queueRear = 0;
pool->shutdown = 0;
//创建线程
error = pthread_create(&pool->managerID,NULL,manager,pool);
if(error != 0)
{
perror("create pthread_create managerID failed");
break;
}
for(int i = 0;i < min; i++)
{
pthread_create(&pool->threadIDs[i],NULL,worker,pool);
if(error != 0)
{
perror("create pthread_create threadIDs failed");
break;
}
}
return pool;
}while(0);
//初始化失败,释放资源
if(pool && pool->threadIDs) free(pool->threadIDs);
if(pool && pool->taskQ) free(pool->taskQ);
if(pool) free(pool);
return NULL;
}
/*
*threadPoolDestroy:销毁线程池
ThreadPool* pool:需要销毁的线程池
返回值:失败返回 -1,成功返回 0;
*/
int threadPoolDestroy(ThreadPool* pool)
{
if(pool == NULL)
{
return -1;
}
//关闭线程池
pool->shutdown = -1;
//阻塞回收管理者线程
pthread_join(pool->managerID,NULL);
//唤醒阻塞的消费者线程 = 工作线程
for(int i = 0; i < pool->liveNum; i++)
{
pthread_cond_signal(&pool->notEmpty);
}
//释放堆内存
if(pool->taskQ)
{
free(pool->taskQ);
}
if(pool->threadIDs)
{
free(pool->threadIDs);
}
//销毁互斥量,条件变量
pthread_mutex_destroy(&pool->mutexPool);
pthread_mutex_destroy(&pool->mutexBusy);
pthread_cond_destroy(&pool->notEmpty);
pthread_cond_destroy(&pool->notFull);
free(pool);
pool = NULL;
return 0;
}
/*
*threadPoolAdd:给线程池添加任务
ThreadPool* pool:线程池
void(*func)(void*):要加到任务中的函数指针
void* arg:要加到任务中的函数指针的参数
返回值:无
*/
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg)
{
pthread_mutex_lock(&pool->mutexPool);
while(pool->queueSize == pool->queueCapacity && !pool->shutdown)
{
//因为任务队列满了或者线程池需要销毁,阻塞生产者线程
pthread_cond_wait(&pool->notFull, &pool->mutexPool);
}
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->mutexPool);
return ;
}
//添加任务
pool->taskQ[pool->queueRear].function = func;
pool->taskQ[pool->queueRear].arg = arg;
pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;
pool->queueSize++;
pthread_cond_signal(&pool->notEmpty);
pthread_mutex_unlock(&pool->mutexPool);
}
/*
*threadPoolBusyNum:获取线程池中工作的线程的个数
ThreadPool* pool:线程池
返回值:当前工作线程个数
*/
int threadPoolBusyNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
return busyNum;
}
/*
*threadPoolBusyNum:获取线程池中活着的线程的个数
ThreadPool* pool:线程池
返回值:当前活着的线程的个数
*/
int threadPoolAliveNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexPool);
int aliveNum = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
return aliveNum;
}
// 工作的线程(消费者线程)任务函数
void* worker(void* arg)
{
ThreadPool * pool = (ThreadPool *) arg;
while(1)
{
pthread_mutex_lock(&pool->mutexPool);
//当前任务队列是否为空
while(pool->queueSize == 0 && !pool->shutdown)
{
//阻塞工作线程
pthread_cond_wait(&pool->notEmpty,&pool->mutexPool);
//判断是否用销毁线程
if(pool->exitNum > 0)
{
pool->exitNum--;
if(pool->liveNum > pool->minNum)
{
pool->liveNum--;
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
}
}
//判断线程池是否被关闭
if(pool->shutdown)
{
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
//从任务队列中取出一个任务
Task task;
task.function = pool->taskQ[pool->queueFront].function;
task.arg = pool->taskQ[pool->queueFront].arg;
//移动头节点
pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
pool->queueSize--;
//解锁
pthread_cond_signal(&pool->notFull);
pthread_mutex_unlock(&pool->mutexPool);
printf("thread %ld start working...\n",pthread_self());
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum++;
pthread_mutex_unlock(&pool->mutexBusy);
//执行
task.function(task.arg);
free(task.arg);
task.arg = NULL;
printf("thread %ld end working...\n",pthread_self());
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum--;
pthread_mutex_unlock(&pool->mutexBusy);
}
return NULL;
}
// 管理者线程任务函数
void* manager(void* arg)
{
ThreadPool * pool = (ThreadPool *)arg;
while(!pool->shutdown)
{
//3s检查一次
sleep(3);
//取出线程池任务的数量和当前线程的数量
pthread_mutex_lock(&pool->mutexPool);
int queueSize = pool->queueSize;
int liveNum = pool->liveNum;
printf("liveNum = %d\n",liveNum);
pthread_mutex_unlock(&pool->mutexPool);
//取出忙的线程的数量
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
printf("busyNum = %d\n",busyNum);
pthread_mutex_unlock(&pool->mutexBusy);
//添加线程
//任务的个数 > 成活的线程个数 && 存活的线程数 < 最大线程数
if(queueSize > liveNum && liveNum < pool->maxNum)
{
pthread_mutex_lock(&pool->mutexPool);
for(int i = 0; i < pool->maxNum && pool->liveNum < pool->maxNum; i++)
{
if(pool->threadIDs[i] == 0)
{
pthread_create(&pool->threadIDs[i],NULL,worker,pool);
pool->liveNum++;
}
}
pthread_mutex_unlock(&pool->mutexPool);
}
//销毁线程
//条件是:忙的线程*2 < 存活的线程数 && 存活的线程 > 最小线程数
//我觉得,释放多余内存
if(busyNum * 2 < liveNum && liveNum > pool->minNum)
{
pthread_mutex_lock(&pool->mutexPool);
liveNum = pool->liveNum;
busyNum = pool->busyNum;
int NUMBER = liveNum-busyNum;
pool->exitNum = NUMBER;
pthread_mutex_unlock(&pool->mutexPool);
//发信号让线程自杀,具体实现就是每个线程的有一个销毁判断
//每次销毁一个,pool->exitNum--,直到为0
for(int i = 0 ;i < NUMBER; i++)
{
pthread_cond_signal(&pool->notEmpty);
}
}
}
return NULL;
}
/*
*threadExit:单个线程退出
ThreadPool* pool:需要退出的线程
*/
void threadExit(ThreadPool* pool)
{
pthread_t tid =pthread_self();
for(int i = 0; i < pool->maxNum; i++)
{
if(pool->threadIDs[i] == tid)
{
pool->threadIDs[i] = 0;
printf("threadExit() called, %ld exiting...\n",tid);
break;
}
}
pthread_exit(NULL);
return;
}
//测试案例
void taskFunc(void * arg)
{
int num = *(int *)arg;
printf("taskFunc thread %ld is working, number = %d\n",pthread_self(),num);
sleep(3);
}
int main()
{
//创建线程池
ThreadPool * pool = threadPoolCreate(5,15,100);
for(int i = 0; i < 100; i++)
{
int * num = (int *)malloc(sizeof(int));
*num = i+100;
threadPoolAdd(pool,taskFunc,num);
}
//主线程等待子线程完成
while(1);
sleep(30);
threadPoolDestroy(pool);
return 0;
}
还不会的小伙伴,认真打一次代码就会了,别直接cv,动手很重要
其中存在调试printf,不需要的可以注释掉
以下为C++版本,因为C++存在面向对象思想,所有实现会更方便,但是概念还是一样的
#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <stdexcept>
#include <condition_variable>
#include <memory> //unique_ptr
#include<assert.h>
const int MAX_THREADS = 1000; //最大线程数目
template <typename T>
class threadPool
{
public:
threadPool(int number = 1);//默认开一个线程
~threadPool();
std::queue<T *> tasks_queue; //任务队列
bool append(T *request);//往请求队列<task_queue>中添加任务<T *>
private:
//工作线程需要运行的函数,不断的从任务队列中取出并执行
static void *worker(void *arg);
void run();
private:
std::vector<std::thread> work_threads; //工作线程
std::mutex queue_mutex;
std::condition_variable condition; //必须与unique_lock配合使用
bool stop;
};//end class
//构造函数,创建线程
template <typename T>
threadPool<T>::threadPool(int number) : stop(false)
{
if (number <= 0 || number > MAX_THREADS)
throw std::exception();
for (int i = 0; i < number; i++)
{
std::cout << "created Thread num is : " << i <<std::endl;
work_threads.emplace_back(worker, this);//添加线程
//直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。
}
}
template <typename T>
inline threadPool<T>::~threadPool()
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
condition.notify_all();
for (auto &ww : work_threads)
ww.join();//可以在析构函数中join
}
//添加任务
template <typename T>
bool threadPool<T>::append(T *request)
{
/*操作工作队列时一定要加锁,因为他被所有线程共享*/
queue_mutex.lock();//同一个类的锁
tasks_queue.push(request);
queue_mutex.unlock();
condition.notify_one(); //线程池添加进去了任务,自然要通知等待的线程
return true;
}
//单个线程
template <typename T>
void *threadPool<T>::worker(void *arg)
{
threadPool *pool = (threadPool *)arg;
pool->run();//线程运行
return pool;
}
template <typename T>
void threadPool<T>::run()
{
while (!stop)
{
std::unique_lock<std::mutex> lk(this->queue_mutex);
/* unique_lock() 出作用域会自动解锁 */
this->condition.wait(lk, [this] { return !this->tasks_queue.empty(); });
//如果任务为空,则wait,就停下来等待唤醒
//需要有任务,才启动该线程,不然就休眠
if (this->tasks_queue.empty())//任务为空,双重保障
{
assert(0&&"断了");//实际上不会运行到这一步,因为任务为空,wait就休眠了。
continue;
}
else
{
T *request = tasks_queue.front();
tasks_queue.pop();
if (request)//来任务了,开始执行
request->process();
}
}
}
#endif
测试代码:
#include "mythread.h"
#include<string>
#include<math.h>
using namespace std;
class Task
{
public:
void process()
{
//cout << "run........." << endl;
//测试任务数量
long i=1000000;
while(i!=0)
{
int j = sqrt(i);
i--;
}
}
};
int main(void)
{
threadPool<Task> pool(6);//6个线程,vector
std::string str;
while (1)
{
Task *tt = new Task();
//使用智能指针
pool.append(tt);//不停的添加任务,任务是队列queue,因为只有固定的线程数
cout<<"添加的任务数量: "<<pool.tasks_queue.size()<<endl;;
delete tt;
}
}
感谢:https://blog.csdn.net/qq_36359022/article/details/78796784