目录
为了方便一些初学同学能更快的实现一个线程池,我这里先给大家一个简单的线程池的代码。本文是一个线程池的基础实现,后续会发进阶版的线程池(添加管理者线程、线程动态扩容缩容等机制)。
本文后面进行线程池基础相关内容的介绍。
线程池代码
头文件 threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*任务结构体*/
typedef struct
{
void (*function)(void *);
void *arg;
} Task;
/*线程池结构体*/
typedef struct
{
pthread_t *threads;
Task *taskQueue;
int threadCount;
int queueSize;
int head;
int tail;
int count;
int shutdown;
pthread_mutex_t lock;
pthread_cond_t notify;
} ThreadPool;
/*任务函数*/
static void exampleTask(void *arg)
{
int *num = (int *)arg;
printf("正在处理数字: %d (线程 ID: %lu)\n", *num, pthread_self());
free(num); /*释放动态分配的内存*/
}
/* 初始化线程池 */
ThreadPool *threadPoolInit(int threadCount, int queueSize);
/* 添加任务到线程池 */
int threadPoolAdd(ThreadPool *pool, void (*function)(void *), void *arg);
/* 销毁线程池 */
int threadPoolDestroy(ThreadPool *pool);
/* 线程工作函数 */
void *threadWork(void *arg);
#endif // THREADPOOL_H
源文件 threadpool.c
#include "threadpool.h"
/* 线程工作函数 */
void *threadWork(void *arg)
{
/* 拿到线程池指针 */
ThreadPool *pool = (ThreadPool *)arg;
while (1)
{
pthread_mutex_lock(&(pool->lock));
/* 线程池未关闭,且线程池为空,等待任务 */
while (pool->count == 0 && !pool->shutdown)
{
pthread_cond_wait(&(pool->notify), &(pool->lock));
}
/* 线程池关闭,解锁、关闭线程 */
if (pool->shutdown)
{
pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL);
}
/* 取出任务 */
Task task;
task.function = pool->taskQueue[pool->head].function;
task.arg = pool->taskQueue[pool->head].arg;
/* 更新队列 */
pool->head = (pool->head + 1) % pool->queueSize;
pool->count--;
pthread_mutex_unlock(&(pool->lock));
/* 执行任务 */
(*(task.function))(task.arg);
}
return NULL;
}
/* 初始化线程池 */
ThreadPool *threadPoolInit(int threadCount, int queueSize)
{
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
if (pool == NULL)
{
return NULL;
}
/* 初始化 */
pool->threadCount = threadCount;
pool->queueSize = queueSize;
pool->head = 0;
pool->tail = 0;
pool->count = 0;
pool->shutdown = 0;
pthread_mutex_init(&(pool->lock), NULL);
pthread_cond_init(&(pool->notify), NULL);
pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * threadCount);
pool->taskQueue = (Task *)malloc(sizeof(Task) * queueSize);
/* 创建工作线程 */
for (int i = 0; i < threadCount; i++)
{
pthread_create(&(pool->threads[i]), NULL, threadWork, (void *)pool);
}
return pool;
}
/* 添加任务到线程池 */
int threadPoolAdd(ThreadPool *pool, void (*function)(void *), void *arg) {
int err = 0;
if (pool == NULL || function == NULL)
{
return -1;
}
pthread_mutex_lock(&(pool->lock));
/* 检查队列是否已满 */
if (pool->count == pool->queueSize)
{
pthread_mutex_unlock(&(pool->lock));
return -1;
}
/* 检查是否已关闭 */
if (pool->shutdown)
{
pthread_mutex_unlock(&(pool->lock));
return -2;
}
/* 添加任务到队列 */
pool->taskQueue[pool->tail].function = function;
pool->taskQueue[pool->tail].arg = arg;
pool->tail = (pool->tail + 1) % pool->queueSize;
pool->count++;
/* 通知一个等待线程 */
pthread_cond_signal(&(pool->notify));
pthread_mutex_unlock(&(pool->lock));
return err;
}
/* 销毁线程池 */
int threadPoolDestroy(ThreadPool *pool)
{
/* 设置关闭标志 */
pool->shutdown = 1;
if (pool == NULL)
{
return -1;
}
pthread_mutex_lock(&(pool->lock));
/* 已关闭则直接返回 */
if (pool->shutdown)
{
pthread_mutex_unlock(&(pool->lock));
return -2;
}
/* 唤醒所有线程 */
pthread_cond_broadcast(&(pool->notify));
pthread_mutex_unlock(&(pool->lock));
/* 等待所有线程退出 */
for (int i = 0; i < pool->threadCount; i++)
{
pthread_join(pool->threads[i], NULL);
}
/* 释放资源 */
free(pool->threads);
free(pool->taskQueue);
/* 销毁锁和条件变量 */
pthread_mutex_destroy(&(pool->lock));
pthread_cond_destroy(&(pool->notify));
free(pool);
return 0;
}
头文件 main.c
#include "threadpool.h"
int main()
{
/*创建线程池:4个线程,任务队列大小为10*/
ThreadPool *pool = threadPoolInit(4, 10);
/*添加20个任务*/
for (int i = 0; i < 20; i++)
{
int *arg = malloc(sizeof(int));
*arg = i;
threadPoolAdd(pool, exampleTask, arg);
}
/*等待所有任务完成*/
sleep(2);
/*销毁线程池*/
threadPoolDestroy(pool);
return 0;
}
线程池相关原理
为什么要用线程池?什么是线程池?
我们正常情况下并发的去处理任务时,通常是每来一个任务我们去创建一个线程为这个任务服务,任务结束的时候又去销毁线程。当然,这样频繁地创建和销毁线程的开销是非常大的,而且这样会导致线程非常分散,不方便我们去管理,也可能会造成线程数量太多,导致系统过载。所以我们就引入了线程池来解决这个问题。
线程池就是在任务开始前,我们提前创建一些线程,当任务来了,我们直接从线程池中取出一个空闲的线程去执行任务。任务执行完毕,将线程再放回线程池中,等待下一个任务到来。这样我们就可以避免频繁的去创建和销毁线程,提高了线程的一个复用性。
线程池的组成
从功能的角度,线程池主要需要三个核心的模块。
- 线程池管理者(PoolController):负责创建、管理和控制线程池。一个线程池不是凭空出现的,我们会先有一个管理者线程去进行线程池的初始化工作和销毁工作,并且在后续根据工作的需求去动态的调整线程池(如动态扩容等)。
- 任务队列(TaskQueue):缓存待执行的任务。由于线程池是我们预先就创建好的,我们还要体现出线程的一个复用的功能。我们需要将任务平均的分配到每个线程上,我们需要在中间做一个缓存的机制,这个就是任务队列。线程池中的空闲线程不断地去任务队列中取任务进行执行,我们就可以将压力平均分到所有线程上。
- 工作线程(ThreadWorkers):实际执行任务的线程。线程池中维护这么一组线程,用于复用的去执行任务。

线程池参数设置
线程池初始化的时候线程数应该设置成多少呢?是越多越好吗?这里是有一个合适的标准的。
| 任务类型 | 推荐初始值 | 原因 |
|---|---|---|
| CPU密集型 | corePoolSize = CPU核数 | 避免过多线程竞争CPU,减少上下文切换开销(如视频编码、数值计算)。 |
| I/O密集型 | corePoolSize = 2*CPU核数 | 线程可能因I/O阻塞(如网络请求、数据库操作),适当增加线程利用率更高。 |
3088

被折叠的 条评论
为什么被折叠?



