概述
线程池分为三个部分:
- 任务队列
- 工作线程,N个(任务队列的消费者)
- 管理者线程,1个
主要实现的函数:
- 创建线程池
- 线程池添加任务
- 销毁线程池
- 任务函数(做什么)
- 工作线程函数
- 管理者线程函数
线程池结构体:
typedef 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,锁整个线程池
pthread_mutex_t mutexBusy; //锁busyNum变量
pthread_cond_t notFull; // pthread _ cond _t表示多线程的条件变量,任务队列是不是满了
pthread_cond_t notEmpty; //任务队列是不是空了int shutdown; //是不是要销毁线程池,销毁为1,不销毁为0
};
创建线程池函数:
ThreadPool* ThreadPoolCreate(int min, int max, int queueSize)
{
ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));
do
{
if (pool == NULL)
{
printf("malloc threadpool fail...n");
break;
}
//开辟工作线程空间
pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t) * max);
if (pool->threadIDs == NULL)
{
printf("malloc threadIDs fail...n");
break;
}
memset(pool->threadIDs, 0, sizeof(pthread_t) * max);
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->notFull, NULL) != 0 ||
pthread_cond_init(&pool->notEmpty, NULL) != 0)
{
printf("mutex or cond init fail...n");
break;
}
//任务队列
pool->taskQ = (Task*)malloc(sizeof(Task) * queueSize);
pool->queueCapacity = queueSize;
pool->queueSize = 0;
pool->queueFront = 0;
pool->queueRear = 0;
pool->shutdown = 0;
//创建管理者线程
pthread_create(&pool->managerID, NULL, manager, pool);
//创建工作线程
for (int i = 0; i < min; i++)
{
pthread_create(&pool->threadIDs[i], NULL, workers, pool);
}
return pool;
} while (0);
//释放资源
if (pool && pool->threadIDs)
{
free(pool->threadIDs);
}
if (pool && pool->taskQ)
{
free(pool->taskQ);
}
if (pool)
{
free(pool);
}
return NULL;
}
工作线程函数:
void* workers(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;
//每取出一个任务后需要移动任务队列的队头:(头指针+1)整除 队列大小
pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
pool->queueSize--;
/*生产者生产了产品之后唤醒消费者,消费者消耗了产品之后唤醒生产者*/
//消费了一个任务,需要唤醒生产者线程
//pthread_cond_signal详解: https://blog.csdn.net/fanyun_01/article/details/106975364
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)
{
//每3秒检查一次
sleep(3);
//取出线程池中当前的任务数和活着的线程数(线程数是共享资源,操作里面的数据需要加锁)
pthread_mutex_lock(&pool->mutexPool);
int queueSize = pool->queueSize;
int liveNum = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
//取出忙的线程数
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
//添加线程:
//1.定义添加线程时机的规则: 任务个数>存活的线程个数 && 存活的线程个数<最大线程数
if (queueSize > liveNum && liveNum < pool->maxNum)
{
int counter = 0;
//切记加锁
pthread_mutex_lock(&pool->mutexPool);
for (int i = 0; i < pool->maxNum && counter < NUMBER && liveNum < pool->maxNum; ++i)
{
if (pool->threadIDs[i] == 0)
{
pthread_create(&pool->threadIDs[i], NULL, workers, pool);
counter++;
pool->liveNum++;
}
}
pthread_mutex_unlock(&pool->mutexPool);
}
//销毁线程
//1.定义销毁线程时机的规则: 忙的个数*2<存活的线程个数 && 存活的线程个数>最小线程数
if (busyNum * 2 < liveNum && liveNum > pool->minNum)
{
//切记加锁
pthread_mutex_lock(&pool->mutexPool);
pool->exitNum = NUMBER;
pthread_mutex_unlock(&pool->mutexPool);
for (int i = 0; i < NUMBER; i++)
{
//这里只能让工作的线程自杀,不能主动销毁工作线程
//使阻塞的线程脱离阻塞状态(pool->notEmpty)
pthread_cond_signal(&pool->notEmpty);
}
}
}
return NULL;
}
线程池任务添加函数:
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);
}
具体实现:
main.c:
#include <stdio.h>
#include"threadpool.h"
#include<pthread.h>
#include<stdlib.h>
#include <unistd.h>
/*
* <cstdio> (stdio.h)
C库执行输入/输出操作:
输入和输出操作也可以在C++实现,通过使用C标准输入和输出库(cstdio,在C语言中称为stdio.h)。
这个库使用流来操作物理设备如键盘,打印机,终端或者系统支持的任何其他类型的文件。
*/
void taskFunc(void* arg)
{
int num = *(int*)arg;
printf("thread %ld is working ,number=%dn", pthread_self(), num);
sleep(1);
}
int main()
{
//创建线程池
ThreadPool* pool = ThreadPoolCreate(3, 10, 100);
for (int i = 0; i < 100; i++)
{
int* num = (int*)malloc(sizeof(int));
*num = i + 100;
threadPoolAdd(pool,taskFunc,num);
}
sleep(30);
ThreadPoolDestroy(pool);
return 0;
}
threadpool.h:
#ifndef _THREADPOOL_H //如果不存在threadpool.h
#define _THREADPOOL_H //就引入threadpool.h
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* workers(void* arg);
//管理线程任务函数
void* manager(void* arg);
//单个线程退出
//否则不需要引入
#endif
threadpool.c:
#include"threadpool.h"
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
const int NUMBER = 2;
//任务结构体
typedef struct Task
{
void(*function)(void* arg); // 函数指针,任务函数
void* arg;
//万能指针,任务函数参数
} Task;
//线程池结构体
typedef 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,锁整个线程池
pthread_mutex_t mutexBusy;
//锁busyNum变量
pthread_cond_t notFull;
// pthread _ cond _t表示多线程的条件变量,任务队列是不是满了
pthread_cond_t notEmpty;
//任务队列是不是空了
int shutdown;
//是不是要销毁线程池,销毁为1,不销毁为0
};
ThreadPool* ThreadPoolCreate(int min, int max, int queueSize)
{
ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));
do
{
if (pool == NULL)
{
printf("malloc threadpool fail...n");
break;
}
//开辟工作线程空间
pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t) * max);
if (pool->threadIDs == NULL)
{
printf("malloc threadIDs fail...n");
break;
}
memset(pool->threadIDs, 0, sizeof(pthread_t) * max);
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->notFull, NULL) != 0 ||
pthread_cond_init(&pool->notEmpty, NULL) != 0)
{
printf("mutex or cond init fail...n");
break;
}
//任务队列
pool->taskQ = (Task*)malloc(sizeof(Task) * queueSize);
pool->queueCapacity = queueSize;
pool->queueSize = 0;
pool->queueFront = 0;
pool->queueRear = 0;
pool->shutdown = 0;
//创建管理者线程
pthread_create(&pool->managerID, NULL, manager, pool);
//创建工作线程
for (int i = 0; i < min; i++)
{
pthread_create(&pool->threadIDs[i], NULL, workers, pool);
}
return pool;
} while (0);
//释放资源
if (pool && pool->threadIDs)
{
free(pool->threadIDs);
}
if (pool && pool->taskQ)
{
free(pool->taskQ);
}
if (pool)
{
free(pool);
}
return NULL;
}
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)
{
//每3秒检查一次
sleep(3);
//取出线程池中当前的任务数和活着的线程数(线程数是共享资源,操作里面的数据需要加锁)
pthread_mutex_lock(&pool->mutexPool);
int queueSize = pool->queueSize;
int liveNum = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
//取出忙的线程数
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
//添加线程:
//1.定义添加线程时机的规则: 任务个数>存活的线程个数 && 存活的线程个数<最大线程数
if (queueSize > liveNum && liveNum < pool->maxNum)
{
int counter = 0;
//切记加锁
pthread_mutex_lock(&pool->mutexPool);
for (int i = 0; i < pool->maxNum && counter < NUMBER && liveNum < pool->maxNum; ++i)
{
if (pool->threadIDs[i] == 0)
{
pthread_create(&pool->threadIDs[i], NULL, workers, pool);
counter++;
pool->liveNum++;
}
}
pthread_mutex_unlock(&pool->mutexPool);
}
//销毁线程
//1.定义销毁线程时机的规则: 忙的个数*2<存活的线程个数 && 存活的线程个数>最小线程数
if (busyNum * 2 < liveNum && liveNum > pool->minNum)
{
//切记加锁
pthread_mutex_lock(&pool->mutexPool);
pool->exitNum = NUMBER;
pthread_mutex_unlock(&pool->mutexPool);
for (int i = 0; i < NUMBER; i++)
{
//这里只能让工作的线程自杀,不能主动销毁工作线程
//使阻塞的线程脱离阻塞状态(pool->notEmpty)
pthread_cond_signal(&pool->notEmpty);
}
}
}
return NULL;
}
void* workers(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;
//每取出一个任务后需要移动任务队列的队头:(头指针+1)整除 队列大小
pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
pool->queueSize--;
/*生产者生产了产品之后唤醒消费者,消费者消耗了产品之后唤醒生产者*/
//消费了一个任务,需要唤醒生产者线程
//pthread_cond_signal详解: https://blog.csdn.net/fanyun_01/article/details/106975364
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 threadExit(ThreadPool* pool)
{
//pthread_self(): https://blog.csdn.net/weixin_43778179/article/details/115219071
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);
}
int threadPoolBusyNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexPool);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexPool);
return busyNum;
}
int threadPoolAliveNum(ThreadPool* pool)
{
pthread_mutex_lock(&pool->mutexPool);
int aliveNum = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
return aliveNum;
}
int ThreadPoolDestroy(ThreadPool* pool)
{
if (pool==NULL)
{
return -1;
}
//关闭线程池
pool->shutdown = 1;
//阻塞生产者
pthread_join(pool->managerID, NULL);
//唤醒阻塞的线程,被唤醒的线程会自动死亡,详情参照205行代码
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->mutexBusy);
pthread_mutex_destroy(&pool->mutexPool);
pthread_cond_destroy(&pool->notEmpty);
pthread_cond_destroy(&pool->notFull);
free(pool);
pool = NULL;
return 0;
}
最后
以上就是轻松小蘑菇为你收集整理的linux 线程池 (C语言实现)线程池分为三个部分:主要实现的函数:的全部内容,希望文章能够帮你解决linux 线程池 (C语言实现)线程池分为三个部分:主要实现的函数:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复