线程池本身只维护「消费者工作线程」,生产者不属于线程池内部成员,但完整业务模型一定同时存在生产者 & 消费者。
C版本
代码

cpp
//threadpool.cpp
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include"threadpool.h"
#include<string.h>
#include<stdlib.h>
//任务队列
struct Task {
void (*function)(void* arg);//定义函数指针,指向函数地址,void* 万能指针,通过强转可以仁义定arg类型义
void* arg;
};
int num=2;//一次增加/减少线程个数
//线程池结构体
struct ThreadPool {
Task* task;//任务队列(环形),指向Task结构体指针,`task` 这个变量保存一块内存的起始地址,可理解为数组
int QueueFront;//队头坐标,取任务
int QueueBehind;//队尾坐边,放任务
int QueueCapacity;//队列最大任务数
int QueueSize;//任务队列现在有的任务数
pthread_t* threadIDs;//工作线程ID,消费者线程
pthread_t managerID;//管理者ID,只有一个
int maxthread;//最多线程数
int minthread;//最少线程数
int livethread;//存活线程
int busythread;//接受任务忙活线程
int exitthread;//要销毁的线程数
int shutdown;//线程池是否要被销毁,销毁1,不销毁0
pthread_mutex_t mutex; // 保护线程池临界资源(队列、liveNum、queueSize等)
pthread_cond_t notfull; // 条件变量:队列**不满**,生产者可以放任务
pthread_cond_t notempty; // 条件变量:队列**不为空**,worker可以取任务
};
void taskfunction(void* arg) {
int number = *(int*) arg;
printf("thread %ld is working, number = %d\n",
pthread_self(), number);
sleep(1);
free(arg);
}
int main() {
//创建线程池
ThreadPool* pool=threadPoolCreate(10,20,3);
for (int i = 0; i < 18; i++) {
int* number = (int*)malloc(sizeof(int));
*number = i;
queueAdd(pool, taskfunction, number);
}
sleep(13);
threadPoolDestroy(pool);
return 0;
}
//创建线程池并初始化,max传入的最多线程数 QueueCapacity队列最大任务数 minthread最少线程数
ThreadPool* threadPoolCreate(int maxthread,int QueueCapacity,int minthread) {
//分配内存!!
ThreadPool* pool= (ThreadPool*)malloc(sizeof(ThreadPool));//创建线程池并开辟堆内存
pool->task = (Task*)malloc(sizeof(Task) * QueueCapacity);//任务队列分配内存
pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t) * maxthread);//给工作线程Id分配内存
//初始化!!
memset(pool->threadIDs, 0, sizeof(pthread_t) * maxthread);
pool->QueueCapacity = QueueCapacity;
pool->QueueSize = 0;
pool->maxthread = maxthread;
pool->minthread = minthread;
pool->QueueFront = 0;
pool->QueueBehind = 0;
pool->busythread = 0;
pool->livethread = minthread;
pool->exitthread = 0;
pool->shutdown = 0;
if (pthread_mutex_init(&pool->mutex, NULL) != 0//=0创建成功
|| pthread_cond_init(&pool->notempty, NULL) != 0
|| pthread_cond_init(&pool->notfull, NULL) != 0) {
printf("mutex or condition init failQAQ\n");
}
//创建线程
pthread_create(&pool->managerID, NULL, manager, pool);//传入pool指针,让子线程能访问线程池
for (int i = 0; i < minthread; i++) {
pthread_create(&pool->threadIDs[i], NULL, worker, pool);
printf("pthread create ID:%ld\n", pool->threadIDs[i]);
}
return pool;
}
//线程退出函数
void ThreadExit(ThreadPool* pool) {
//获取当前线程Id
pthread_t tid = pthread_self();
//循环在线程id数组里面找到该线程id,把他置为0
for (int i = 0; i < pool->maxthread; i++) {
if (pool->threadIDs[i] == tid) {
pool->threadIDs[i] = 0;
break;
}
}
//主动结束当前正在运行的这条线程
printf("threadexit ID:%ld\n", tid);
pthread_exit(NULL);
}
//线程池销毁函数
void threadPoolDestroy(ThreadPool* pool) {
//此时才意识到为什么要加上shudown变量来判断线程池是否要被销毁
//通过shutdowm就能判断代码其他函数线程运行时需不需要被销毁
if (pool == NULL) {
printf("threadpool is NULL\n");
return;
}
pool->shutdown = 1;
//等待manager线程自己运行结束,然后回收它的资源
pthread_join(pool->managerID, NULL);
//循环遍历每一个活着线程(线程退出了就不是活着了),让他们都退出
for (int i = 0; i < pool->livethread; i++) {
pthread_cond_broadcast(&pool->notempty);
}
//释放堆内存
if (pool->task) {
free(pool->task);
}
if (pool->threadIDs) {
free(pool->threadIDs);
}
//销毁互斥锁条件变量
pthread_mutex_destroy(&pool->mutex);
pthread_cond_destroy(&pool->notempty);
pthread_cond_destroy(&pool->notfull);
//释放线程池
free(pool);
//pool置空防止产生野指针
pool = NULL;
}
//管理者操作函数
void* manager(void* arg) {
ThreadPool* pool = (ThreadPool*)arg;
while (1) {
//每隔三面检查一次
sleep(3);
//获取变量
pthread_mutex_lock(&pool->mutex);
//检查是否要关闭线程池
if (pool->shutdown == 1) {
pthread_mutex_unlock(&pool->mutex);
printf("namagerclose managerID:%ld\n", pthread_self());
return NULL;
}
int livethread = pool->livethread;
int busythread = pool->busythread;
int QueueSize = pool->QueueSize;
int maxthread = pool->maxthread;
int minthread = pool->minthread;
//增加线程
if (livethread < QueueSize && livethread < maxthread) {
int count = 0;//用于记录增加的线程数
for (int i = 0; i < maxthread&&count<num&& livethread < maxthread; i++) {
if (pool->threadIDs[i] == 0) {
pthread_create(&pool->threadIDs[i], NULL, worker, pool);
printf("live:%d queuesize:%d addthread ID:%ld\n",pool->livethread,pool->QueueSize,pool->threadIDs[i]);
count++;
pool->livethread++;
}
}
}
//销毁线程
if (busythread * 2 < livethread && livethread > minthread) {
pool->exitthread += num;
//让线程自杀
for (int i = 0; i < num; i++) {
pthread_cond_signal(&pool->notempty);//唤醒notempty条件变量
}
}
pthread_mutex_unlock(&pool->mutex);
}
}
//工作线程(消费者)操作函数
void* worker(void* arg) {
ThreadPool* pool =(ThreadPool*)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
//判断任务队列是否为空
while (pool->QueueSize == 0&&pool->shutdown==0) {
pthread_cond_wait(&pool->notempty, &pool->mutex);//阻塞等待不为空时唤醒
//判断是否要销毁线程
if (pool->exitthread > 0) {
pool->exitthread--;
pool->livethread--;
printf("busy:%d,live:%d destroy estra thread:%ld\n",pool->busythread,pool->livethread,pthread_self());
pthread_mutex_unlock(&pool->mutex);
ThreadExit(pool);
}
}
//是否要关闭线程池
if (pool->shutdown == 1) {
pthread_mutex_unlock(&pool->mutex);
ThreadExit(pool);
}
//从队列中取任务
Task task;
task.function = pool->task[pool->QueueFront].function;
task.arg = pool->task[pool->QueueFront].arg;
//取完一个任务,头坐标要动态移动
pool->QueueFront = (pool->QueueFront + 1) % pool->QueueCapacity;
pool->QueueSize--;
pool->busythread++;
printf("threadID:%ld get task\n", pthread_self());
//取完告诉生产者 不满 可以生产了
pthread_cond_signal(&pool->notfull);
pthread_mutex_unlock(&pool->mutex);
//执行任务
task.function(task.arg);
pthread_mutex_lock(&pool->mutex);
pool->busythread--;
pthread_mutex_unlock(&pool->mutex);
}
return NULL;
}
//增加任务函数
void queueAdd(ThreadPool* pool, void (*function)(void*),void* arg) {
pthread_mutex_lock(&pool->mutex);
//判断任务队列是否满了
while(pool->QueueSize == pool->QueueCapacity) {
pthread_cond_wait(&pool->notfull,&pool->mutex);
}
//队列中添加任务
pool->task[pool->QueueBehind].function = function;
pool->task[pool->QueueBehind].arg = arg;
pool->QueueBehind = (pool->QueueBehind + 1) % pool->QueueCapacity;
pool->QueueSize++;
printf("add task\n");
//唤醒消费者
pthread_cond_signal(&pool->notempty);
pthread_mutex_unlock(&pool->mutex);
}
cpp
//threadpool.h
#pragma once
#ifndef _THREADPOOL_H
#define _THREADPOOL_H
typedef struct ThreadPool ThreadPool;
//管理者操作函数
void* manager(void* arg);
//创建线程池并初始化
ThreadPool* threadPoolCreate(int maxthread,int QueueCapacity,int minthread);
//线程退出
void ThreadExit(ThreadPool* pool);
//增加任务函数
void queueAdd(ThreadPool* pool, void (*function)(void*), void* arg);
//工作线程(消费者)操作函数
void* worker(void* arg);
//线程池销毁函数
void threadPoolDestroy(ThreadPool* pool);
#endif // _THREADPOOL_H
函数指针:
void (*function)(void* arg) 是函数指针变量 ,用来存放回调函数地址;void* function(void* arg)只是一个函数声明,表示该函数执行后返回万能指针,二者语法含义完全不同。


关于livenum和busynum


解释为什么manager中增加线程的方式是
任务的个数>存活的线程个数 && 存活的线程数<最大线程数
任务个数:任务队列还没有被领走的任务,代表存活着的线程数不够,我们当然想多增加线程把这些任务领走
销毁线程:
忙的线程*2 < 存活的线程数 && 存活的线程>最小线程数
忙的线程是真正处理任务的,明显空闲下来线程太多了,占用资源,销毁!!!
不在manager里面销毁


相当于我们要在工作线程中去判断当前线程是不是空闲的,然后自杀
销毁线程池核心目标:
安全停止所有线程 → 回收线程资源 → 释放堆内存 → 销毁锁和条件变量,防止内存泄漏 流程顺序原则:先标记关闭信号 → 回收管理线程 → 唤醒所有工作线程退出 → 释放资源
打关闭标记 → 等管理线程退出 → 唤醒所有工作线程退出 → 回收全部线程资源 → 释放堆内存 → 销毁锁与条件变量
C++版本
代码

cpp
//main.cpp
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include"Task.h"
#include "pthreadpool.h"
void taskfunction(void* arg) {
int* p = static_cast<int*>(arg);
int num = *p;
printf("thread %ld working, num=%d\n", pthread_self(), num);
sleep(1);
delete p; // 释放真正的int指针
}
int main() {
//创建线程池
ThreadPool* pool = new ThreadPool(10,3);
for (int i = 0; i < 18; i++) {
int* number = new int;
*number = i;
Task t;
t.function = taskfunction;
t.arg = number;
// 传入完整Task对象
pool->addTask(t);
}
sleep(13);
delete pool;
return 0;
}
cpp
//pthreadpool.cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include"pthreadpool.h"
#include<string.h>
//任务队列
int num = 2;//一次增加/减少线程个数
//创建线程池并初始化,max传入的最多线程数,minthread最少线程数
ThreadPool::ThreadPool(int maxthread, int minthread) {
//实例化Task
m_taskQueue = new TaskQueue;
//给threadid开辟一段堆内存
threadIDs = new pthread_t[maxthread];
//初始化!!
memset(threadIDs, 0, sizeof(pthread_t) * maxthread);
this->maxthread = maxthread;
this->minthread = minthread;
busythread = 0;
livethread = minthread;
exitthread = 0;
shutdown = 0;
if (pthread_mutex_init(&mutex, NULL) != 0//=0创建成功
|| pthread_cond_init(¬empty, NULL) != 0) {
printf("mutex or condition init failQAQ\n");
}
//创建线程
pthread_create(&managerID, NULL, manager, this);//传入pool指针,让子线程能访问线程池
for (int i = 0; i < minthread; i++) {
pthread_create(&threadIDs[i], NULL, worker, this);
printf("pthread create ID:%ld\n", threadIDs[i]);
}
}
//线程池销毁函数
ThreadPool::~ThreadPool() {
//此时才意识到为什么要加上shudown变量来判断线程池是否要被销毁
//通过shutdowm就能判断代码其他函数线程运行时需不需要被销毁
shutdown = 1;
//等待manager线程自己运行结束,然后回收它的资源
pthread_join(managerID, NULL);
//循环遍历每一个活着线程(线程退出了就不是活着了),让他们都退出
for (int i = 0; i < livethread; i++) {
pthread_cond_broadcast(¬empty);
}
//释放堆内存
if (m_taskQueue) {
delete m_taskQueue;
}
if (threadIDs) {
delete threadIDs;
}
//销毁互斥锁条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(¬empty);
}
//添加任务
void ThreadPool::addTask(Task& task) {
if (shutdown) {
return;
}
m_taskQueue->addTask(task);
pthread_cond_signal(¬empty);
}
//线程退出函数
void ThreadPool::ThreadExit() {
//获取当前线程Id
pthread_t tid = pthread_self();
//循环在线程id数组里面找到该线程id,把他置为0
for (int i = 0; i < maxthread; i++) {
if (threadIDs[i] == tid) {
threadIDs[i] = 0;
break;
}
}
//主动结束当前正在运行的这条线程
printf("threadexit ID:%ld\n", tid);
pthread_exit(NULL);
}
//管理者操作函数
void* ThreadPool::manager(void* arg) {
ThreadPool* pool = (ThreadPool*)arg;
while (1) {
//每隔三面检查一次
sleep(3);
//获取变量
pthread_mutex_lock(&pool->mutex);
//检查是否要关闭线程池
if (pool->shutdown == 1) {
pthread_mutex_unlock(&pool->mutex);
printf("namagerclose managerID:%ld\n", pthread_self());
return NULL;
}
int livethread = pool->livethread;
int busythread = pool->busythread;
int maxthread = pool->maxthread;
int minthread = pool->minthread;
//增加线程
if (livethread < pool->m_taskQueue->getSize() && livethread < maxthread) {
int count = 0;//用于记录增加的线程数
for (int i = 0; i < maxthread && count < num && livethread < maxthread; i++) {
if (pool->threadIDs[i] == 0) {
pthread_create(&pool->threadIDs[i], NULL, worker, pool);
printf("live:%d queuesize:%d addthread ID:%ld\n", pool->livethread, pool->m_taskQueue->getSize(), pool->threadIDs[i]);
count++;
pool->livethread++;
}
}
}
//销毁线程
if (busythread * 2 < livethread && livethread > minthread) {
pool->exitthread += num;
//让线程自杀
for (int i = 0; i < num; i++) {
pthread_cond_signal(&pool->notempty);//唤醒notempty条件变量
}
}
pthread_mutex_unlock(&pool->mutex);
}
}
//工作线程(消费者)操作函数
void* ThreadPool::worker(void* arg) {
ThreadPool* pool = (ThreadPool*)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
//判断任务队列是否为空
while (pool->m_taskQueue->getSize() == 0 && pool->shutdown == 0) {
pthread_cond_wait(&pool->notempty, &pool->mutex);//阻塞等待不为空时唤醒
//判断是否要销毁线程
if (pool->exitthread > 0) {
pool->exitthread--;
pool->livethread--;
printf("busy:%d,live:%d destroy estra thread:%ld\n", pool->busythread, pool->livethread, pthread_self());
pthread_mutex_unlock(&pool->mutex);
pool->ThreadExit();
}
}
//是否要关闭线程池
if (pool->shutdown == 1) {
pthread_mutex_unlock(&pool->mutex);
pool->ThreadExit();
}
//从队列中取任务
Task task;
task = pool->m_taskQueue->takeTask();
pool->busythread++;
printf("threadID:%ld get task\n", pthread_self());
pthread_mutex_unlock(&pool->mutex);
//执行任务
task.function(task.arg);
pthread_mutex_lock(&pool->mutex);
pool->busythread--;
pthread_mutex_unlock(&pool->mutex);
//delete task.arg;
}
return nullptr;
}
cpp
//pthreadpool.h
#pragma once
#include "Task.h"
//线程池类
class ThreadPool {
public:
//线程池初始化
ThreadPool(int maxthread,int minthread);
//线程池销毁
~ThreadPool();
//添加任务
void addTask(Task& task);
private:
//工作线程
static void* worker(void* arg);
//管理者线程
static void* manager(void* arg);
//线程退出函数
void ThreadExit();
TaskQueue* m_taskQueue;
pthread_t* threadIDs;//工作线程ID,消费者线程
pthread_t managerID;//管理者ID,只有一个
int maxthread;//最多线程数
int minthread;//最少线程数
int livethread;//存活线程
int busythread;//接受任务忙活线程
int exitthread;//要销毁的线程数
int shutdown;//线程池是否要被销毁,销毁1,不销毁0
pthread_mutex_t mutex; // 保护线程池临界资源(队列、liveNum、queueSize等)
pthread_cond_t notempty; // 条件变量:队列**不为空**,worker可以取任务
};
cpp
//Task.cpp
#include<iostream>
#include"Task.h"
#include "pthreadpool.h"
TaskQueue::TaskQueue(){
pthread_mutex_init(&m_mutex, NULL);
}
TaskQueue::~TaskQueue() {
pthread_mutex_destroy(&m_mutex);
}
//增加任务函数
void TaskQueue::addTask(Task& task) {
pthread_mutex_lock(&m_mutex);
m_queue.push(task);
printf("add task\n");
pthread_mutex_unlock(&m_mutex);
}
//取出任务函数
Task TaskQueue::takeTask() {
Task t;
pthread_mutex_lock(&m_mutex);
t= m_queue.front();
m_queue.pop();
printf("threadID:%ld get task\n", pthread_self());
pthread_mutex_unlock(&m_mutex);
return t;
}
//获取队列任务个数
int TaskQueue::getSize() {
int s;
pthread_mutex_lock(&m_mutex);
s = m_queue.size();
pthread_mutex_unlock(&m_mutex);
return s;
}
cpp
//Task.h
#pragma once
#include <queue>
#include <pthread.h>
using callback = void(*)(void*);
struct Task {
//无参构造,初始化任务
Task() {
function = nullptr;
arg = nullptr;
}
callback function;
void* arg;
};
//任务队列类,任务队列,放任务,取任务,锁
class TaskQueue {
public:
//初始化锁
TaskQueue();
//释放锁
~TaskQueue();
//增加任务函数
void addTask(Task& task);
//取出任务函数
Task takeTask();
//获取队列任务个数
int getSize();
private:
std::queue<Task> m_queue;
pthread_mutex_t m_mutex;
};
关于头文件源文件

new 自定义类:开内存 + 调用构造函数,受访问控制(public/private 约束)new 基础类型[]:只开一块内存,没有构造函数调用,不受 private 限制
关于释放堆内存析构不要判断if线程池为空



总而言之,只要执行到析构函数,对象一定不可能空
worker manager前面要加static:
关于为什么workermanager里面要重新
