一、线程池介绍
1)应用场景
当并发数很多的时候,并且每个线程执行时间很短的任务,这样就会频繁创建线程,而这样的频繁创建和销毁线程会大大降低系统的执行效率。对于这种场景我们可以使用线程池来复用之前创建的线程,降低线程的频繁创建和销毁工作,达到提高执行效率的目的。
2)线程池原理
线程池使用者往线程池任务队列里面添加任务,线程池会根据任务的多少来自动创建或销毁工作线程取执行任务,即当任务数量比较多而线程池比较少处于忙不过来的状态时,线程池就会自动创建线程,而当仍务数量比较少而空闲线程比较多时,线程池就会自动销毁一部分空闲线程。其中任务队列、线程池使用者和工作线程组成一个生产者消费者模型,线程池使用者(消费者)检查队列已满就阻塞,否则就向任务队列添加任务并通知工作线程(消费者)取任务执行,而工作线程(消费者)取任务之后也会向线程池使用者(生产者)发送通知解阻塞。
3)线程池结构
线程池由任务队列
、工作线程
和管理线程
三部分组成,他们的所用分别如下。
- 任务队列:
- 负责保存要执行的任务(一般每个任务就是一个回调函数);
- 线程池使用者(生产者)往任务队列里面添加任务,并通知工作线程(消费者)取任务执行;
- 工作线程(消费者)从任务队列里面获取到任务后,需要把该任务从队列中删除;
- 工作线程:
- 负责执行任务队列里面的任务;
- 当任务队列没有任务时,工作线程便自动睡眠防止占用CPU资源;
- 当由任务时唤醒工作线程,从队列中取任务执行(从队列中取出任务后,如果生产者此时阻塞的话可以通知生产者解阻塞);
- 管理线程:
- 负责控制工作线程的数量;
- 当空闲的工作线程数量比较多时,就销毁一部分线程;
- 当队列任务比较多而工作线程比较少时,新创建一部分线程;
二、程序实现
1)C语言实现
threadPool.h
#ifndef _THREAD_POOL_
#define _THREAD_POOL_
typedef struct ThreadPool ThreadPool;
// 创建并初始化线程池
ThreadPool* threadPoolCreate(int queueSize, int minNum, int maxNum);
// 销毁线程池
void threadPoolDestory(ThreadPool* pool);
// 往线程池添加任务
int threadPoolAdd(ThreadPool* pool, void (*handler)(void* arg), void* arg);
// 获取线程池当前工作线程数
int threadPoolWorkNum(ThreadPool* pool);
// 获取线程池当前存活线程数
int threadPoolLiveNum(ThreadPool* pool);
#endif // _THREAD_POOL_
threadPool.c
#include "threadPool.h"
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#define CHAGNUM 4
void* worker(void *arg);
void* manager(void *arg);
void threadExit(ThreadPool* pool);
typedef struct Task {
void (*handler)(void* arg);
void* arg;
}Task;
struct ThreadPool {
Task* taskQ;
int qCapacity;
int qSize;
int qFront;
int qBack;
pthread_t manageID;
pthread_t* workIDs;
int maxNum; // 最大线程数量
int minNum; // 最小线程数量
int workNum; // 正在执行任务的工作线程数量
int liveNum; // 当前已创建的的工作线程数量
int exitNum; // 需要销毁退出的线程数量
pthread_mutex_t mutexPool;
pthread_mutex_t mutexWork; // 锁workNum变量
pthread_cond_t hasTask; // 任务队列是否有任务
pthread_cond_t isFull; // 任务队列是否已满
int isDestory; // 线程池是否销毁
};
ThreadPool* threadPoolCreate(int queueSize, int minNum, int maxNum)
{
int i, res = 0;
// 创建线程池对象
ThreadPool* tPool = (ThreadPool*)malloc(sizeof(struct ThreadPool));
if (tPool == NULL) {
perror("tPool malloc:");
goto err;
}
// 创建任务队列
tPool->taskQ = (Task*)malloc(sizeof(struct Task) * queueSize);
if (tPool->taskQ == NULL) {
perror("taskQ malloc:");
goto err;
}
tPool->qSize = 0;
tPool->qCapacity = queueSize;
tPool->qFront = tPool->qBack = 0;
// 创建存储工作线程ID的数组
tPool->workIDs = (pthread_t*)malloc(sizeof<