线程池(Thread Pool) 是一种多线程处理模式,预先创建一定数量的线程,将任务放入队列中,由空闲线程从队列中取出任务执行。
核心优势:
线程池工作流程:
任务提交 → 任务队列 → 工作线程取任务 → 执行任务 → 返回等待新任务
三大核心组件:
┌─────────────────────────────────────────────────────────┐
│ 线程池管理器 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 工作线程1 │ │ 工作线程2 │ │ 工作线程N │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ │ │
│ ┌─────┴─────┐ │
│ │ 任务队列 │ │
│ └───────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 任务结构体(函数指针+参数) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
组件职责:
| 组件 | 职责 | 关键技术 |
|---|---|---|
| 任务结构体 | 封装任务函数和参数 | 函数指针、void*参数 |
| 任务队列 | 存储待执行的任务 | 链表或数组实现 |
| 工作线程 | 从队列取任务并执行 | while循环、条件变量 |
| 管理线程 | 监控和管理线程池 | 动态调整线程数、销毁线程池 |
// 任务结构体:封装任务函数和参数
typedef struct {
void (*function)(void *arg); // 任务函数指针
void *arg; // 任务参数
} Task;
设计要点:
链表实现(推荐):
typedef struct TaskNode {
Task task;
struct TaskNode *next;
} TaskNode;
typedef struct {
TaskNode *head;
TaskNode *tail;
int count;
} TaskQueue;
数组实现(固定大小):
#define MAX_QUEUE_SIZE 100
typedef struct {
Task tasks[MAX_QUEUE_SIZE];
int front;
int rear;
int count;
} TaskQueue;
链表 vs 数组:
| 特性 | 链表 | 数组 |
|---|---|---|
| 动态扩展 | 支持 | 不支持 |
| 内存开销 | 额外指针开销 | 固定大小 |
| 缓存友好性 | 较差 | 较好 |
| 实现复杂度 | 较高 | 较低 |
互斥锁 + 条件变量实现:
pthread_mutex_t queue_lock;
pthread_cond_t queue_not_empty;
pthread_cond_t queue_not_full;
// 入队操作
void enqueue(Task task) {
pthread_mutex_lock(&queue_lock);
// 如果队列满,等待
while (queue_full()) {
pthread_cond_wait(&queue_not_full, &queue_lock);
}
// 添加任务到队列
// ...
// 通知工作线程有新任务
pthread_cond_signal(&queue_not_empty);
pthread_mutex_unlock(&queue_lock);
}
// 出队操作
Task dequeue() {
pthread_mutex_lock(&queue_lock);
// 如果队列空,等待
while (queue_empty() && !shutdown) {
pthread_cond_wait(&queue_not_empty, &queue_lock);
}
// 从队列取出任务
// ...
// 通知管理线程队列有空间
pthread_cond_signal(&queue_not_full);
pthread_mutex_unlock(&queue_lock);
return task;
}
void *worker_thread(void *arg) {
ThreadPool *pool = (ThreadPool *)arg;
while (1) {
// 从队列获取任务
Task task = dequeue(pool);
// 如果收到关闭信号,退出
if (task.function == NULL) {
break;
}
// 执行任务
task.function(task.arg);
// 释放任务内存
free(task.arg);
}
return NULL;
}
网络请求处理:
定时任务调度:
后台任务处理:
#include <pthread.h>
#include <stdlib.h>
// 线程池结构体
typedef struct {
pthread_t *threads; // 工作线程数组
int thread_count; // 工作线程数量
TaskNode *task_head; // 任务队列头指针
TaskNode *task_tail; // 任务队列尾指针
int task_count; // 当前任务数量
pthread_mutex_t queue_lock; // 队列互斥锁
pthread_cond_t not_empty; // 队列非空条件变量
pthread_cond_t not_full; // 队列未满条件变量
int max_queue_size; // 最大队列长度
volatile int shutdown; // 关闭标志
} ThreadPool;
// 创建线程池
ThreadPool *thread_pool_create(int thread_count, int max_queue_size);
// 向线程池提交任务
int thread_pool_submit(ThreadPool *pool, void (*function)(void *arg), void *arg);
// 销毁线程池
int thread_pool_destroy(ThreadPool *pool);
// 互斥锁
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
// 条件变量
pthread_cond_init(&cond, NULL);
pthread_cond_wait(&cond, &mutex); // 等待条件
pthread_cond_signal(&cond); // 唤醒一个等待线程
pthread_cond_broadcast(&cond); // 唤醒所有等待线程
pthread_cond_destroy(&cond);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define DEFAULT_THREAD_COUNT 4
#define DEFAULT_MAX_QUEUE_SIZE 100
// 任务结构体
typedef struct {
void (*function)(void *arg); // 任务函数指针
void *arg; // 任务参数
} Task;
// 任务节点(链表)
typedef struct TaskNode {
Task task;
struct TaskNode *next;
} TaskNode;
// 线程池结构体
typedef struct {
pthread_t *threads; // 工作线程数组
int thread_count; // 工作线程数量
TaskNode *task_head; // 任务队列头指针
TaskNode *task_tail; // 任务队列尾指针
int task_count; // 当前任务数量
pthread_mutex_t queue_lock; // 队列互斥锁
pthread_cond_t not_empty; // 队列非空条件变量
pthread_cond_t not_full; // 队列未满条件变量
int max_queue_size; // 最大队列长度
volatile int shutdown; // 关闭标志
} ThreadPool;
// 创建线程池
ThreadPool *thread_pool_create(int thread_count, int max_queue_size) {
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
if (pool == NULL) {
return NULL;
}
// 初始化参数
pool->thread_count = thread_count;
pool->max_queue_size = max_queue_size;
pool->task_head = NULL;
pool->task_tail = NULL;
pool->task_count = 0;
pool->shutdown = 0;
// 初始化同步原语
pthread_mutex_init(&pool->queue_lock, NULL);
pthread_cond_init(&pool->not_empty, NULL);
pthread_cond_init(&pool->not_full, NULL);
// 分配线程数组
pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count);
if (pool->threads == NULL) {
free(pool);
return NULL;
}
// 创建工作线程
for (int i = 0; i < thread_count; i++) {
if (pthread_create(&pool->threads[i], NULL, worker_thread, pool) != 0) {
// 创建失败,清理已创建的线程
pool->shutdown = 1;
for (int j = 0; j < i; j++) {
pthread_join(pool->threads[j], NULL);
}
free(pool->threads);
pthread_mutex_destroy(&pool->queue_lock);
pthread_cond_destroy(&pool->not_empty);
pthread_cond_destroy(&pool->not_full);
free(pool);
return NULL;
}
}
printf("Thread pool created with %d threads\n", thread_count);
return pool;
}
// 工作线程函数
void *worker_thread(void *arg) {
ThreadPool *pool = (ThreadPool *)arg;
while (1) {
// 加锁
pthread_mutex_lock(&pool->queue_lock);
// 等待任务或关闭信号
while (pool->task_count == 0 && !pool->shutdown) {
pthread_cond_wait(&pool->not_empty, &pool->queue_lock);
}
// 如果收到关闭信号且队列为空,退出
if (pool->shutdown && pool->task_count == 0) {
pthread_mutex_unlock(&pool->queue_lock);
break;
}
// 取出任务
TaskNode *node = pool->task_head;
pool->task_head = node->next;
if (pool->task_head == NULL) {
pool->task_tail = NULL;
}
pool->task_count--;
// 通知管理线程队列有空间
pthread_cond_signal(&pool->not_full);
pthread_mutex_unlock(&pool->queue_lock);
// 执行任务
node->task.function(node->task.arg);
// 释放任务节点
free(node->task.arg); // 释放参数
free(node); // 释放节点
}
return NULL;
}
// 向线程池提交任务
int thread_pool_submit(ThreadPool *pool, void (*function)(void *arg), void *arg) {
if (pool == NULL || function == NULL) {
return -1;
}
// 创建任务节点
TaskNode *node = (TaskNode *)malloc(sizeof(TaskNode));
if (node == NULL) {
return -1;
}
node->task.function = function;
node->task.arg = arg;
node->next = NULL;
// 加锁
pthread_mutex_lock(&pool->queue_lock);
// 等待队列有空间
while (pool->task_count >= pool->max_queue_size && !pool->shutdown) {
pthread_cond_wait(&pool->not_full, &pool->queue_lock);
}
// 如果已关闭,拒绝新任务
if (pool->shutdown) {
pthread_mutex_unlock(&pool->queue_lock);
free(node);
return -1;
}
// 添加任务到队列
if (pool->task_tail == NULL) {
pool->task_head = node;
pool->task_tail = node;
} else {
pool->task_tail->next = node;
pool->task_tail = node;
}
pool->task_count++;
// 通知工作线程有新任务
pthread_cond_signal(&pool->not_empty);
pthread_mutex_unlock(&pool->queue_lock);
return 0;
}
// 销毁线程池
int thread_pool_destroy(ThreadPool *pool) {
if (pool == NULL) {
return -1;
}
// 设置关闭标志
pthread_mutex_lock(&pool->queue_lock);
pool->shutdown = 1;
pthread_mutex_unlock(&pool->queue_lock);
// 唤醒所有工作线程
pthread_cond_broadcast(&pool->not_empty);
// 等待所有工作线程退出
for (int i = 0; i < pool->thread_count; i++) {
pthread_join(pool->threads[i], NULL);
}
// 清理剩余任务
while (pool->task_head != NULL) {
TaskNode *node = pool->task_head;
pool->task_head = node->next;
free(node->task.arg);
free(node);
}
// 释放资源
free(pool->threads);
pthread_mutex_destroy(&pool->queue_lock);
pthread_cond_destroy(&pool->not_empty);
pthread_cond_destroy(&pool->not_full);
free(pool);
printf("Thread pool destroyed\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
// 线程池结构体和函数(同上)
// ... (这里省略,实际使用时需要包含完整的线程池实现)
// 任务参数结构体
typedef struct {
int task_id;
char description[64];
} TaskArg;
// 示例任务函数1:计算任务
void calculate_task(void *arg) {
TaskArg *task_arg = (TaskArg *)arg;
printf("[Task %d] Calculating... %s\n", task_arg->task_id, task_arg->description);
// 模拟计算
long result = 0;
for (int i = 0; i < 1000000; i++) {
result += i;
}
printf("[Task %d] Result: %ld\n", task_arg->task_id, result);
}
// 示例任务函数2:IO任务
void io_task(void *arg) {
TaskArg *task_arg = (TaskArg *)arg;
printf("[Task %d] Performing IO... %s\n", task_arg->task_id, task_arg->description);
// 模拟IO操作
usleep(100000); // 100ms
printf("[Task %d] IO completed\n", task_arg->task_id);
}
// 示例任务函数3:网络任务
void network_task(void *arg) {
TaskArg *task_arg = (TaskArg *)arg;
printf("[Task %d] Sending network request... %s\n",
task_arg->task_id, task_arg->description);
// 模拟网络请求
usleep(200000); // 200ms
printf("[Task %d] Network response received\n", task_arg->task_id);
}
int main() {
// 创建线程池:4个工作线程,最大100个任务
ThreadPool *pool = thread_pool_create(4, 100);
if (pool == NULL) {
fprintf(stderr, "Failed to create thread pool\n");
return 1;
}
// 提交任务
const char *descriptions[] = {
"Heavy computation",
"File read/write",
"HTTP request",
"Database query",
"Image processing"
};
for (int i = 0; i < 10; i++) {
// 分配任务参数
TaskArg *arg = (TaskArg *)malloc(sizeof(TaskArg));
arg->task_id = i;
strcpy(arg->description, descriptions[i % 5]);
// 根据任务ID选择不同的任务函数
void (*task_func)(void *);
switch (i % 3) {
case 0: task_func = calculate_task; break;
case 1: task_func = io_task; break;
case 2: task_func = network_task; break;
default: task_func = calculate_task;
}
// 提交任务
if (thread_pool_submit(pool, task_func, arg) != 0) {
fprintf(stderr, "Failed to submit task %d\n", i);
free(arg);
} else {
printf("Submitted task %d\n", i);
}
usleep(50000); // 50ms间隔提交
}
// 等待任务完成
sleep(5);
// 销毁线程池
thread_pool_destroy(pool);
return 0;
}
将线程池实现和使用示例保存为threadpool_demo.c,然后编译运行:
gcc -pthread -o threadpool_demo threadpool_demo.c
./threadpool_demo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
// 线程池结构体和函数(同上)
// ... (这里省略,实际使用时需要包含完整的线程池实现)
// HTTP请求结构体
typedef struct {
int client_fd;
char method[16];
char path[256];
char *body;
} HttpRequest;
// 处理HTTP请求的任务函数
void handle_http_request(void *arg) {
HttpRequest *req = (HttpRequest *)arg;
printf("[HTTP] Handling request: %s %s\n", req->method, req->path);
// 模拟处理时间
usleep(50000); // 50ms
// 构建响应
char response[1024];
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<html><body>"
"<h1>Hello from Thread Pool!</h1>"
"<p>Request: %s %s</p>"
"</body></html>",
req->method, req->path);
// 发送响应(模拟)
printf("[HTTP] Response sent: %zu bytes\n", strlen(response));
// 关闭连接(模拟)
close(req->client_fd);
// 释放请求体
if (req->body) {
free(req->body);
}
free(req);
}
// 模拟TCP服务器
void simulate_tcp_server(void) {
printf("=== TCP Server Simulation ===\n");
// 创建线程池:4个工作线程,最大50个连接
ThreadPool *pool = thread_pool_create(4, 50);
if (pool == NULL) {
fprintf(stderr, "Failed to create thread pool\n");
return;
}
// 模拟接收10个客户端连接
for (int i = 0; i < 10; i++) {
HttpRequest *req = (HttpRequest *)malloc(sizeof(HttpRequest));
req->client_fd = 100 + i; // 模拟文件描述符
strcpy(req->method, "GET");
snprintf(req->path, sizeof(req->path), "/page%d.html", i);
req->body = NULL;
// 提交任务到线程池
if (thread_pool_submit(pool, handle_http_request, req) != 0) {
fprintf(stderr, "Failed to submit HTTP request %d\n", i);
free(req);
} else {
printf("Accepted connection %d\n", i);
}
usleep(10000); // 10ms间隔
}
// 等待所有请求处理完成
sleep(3);
// 销毁线程池
thread_pool_destroy(pool);
}
int main() {
simulate_tcp_server();
return 0;
}
编译运行:
gcc -pthread -o http_server http_server.c
./http_server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
// 线程池结构体和函数(同上)
// ... (这里省略,实际使用时需要包含完整的线程池实现)
// 定时任务结构体
typedef struct {
int task_id;
int interval_ms; // 执行间隔(毫秒)
int count; // 执行次数
void (*task_func)(void *arg);
void *arg;
} TimerTask;
// 定时任务执行函数
void timer_task_executor(void *arg) {
TimerTask *timer = (TimerTask *)arg;
printf("[Timer %d] Starting, interval=%dms, count=%d\n",
timer->task_id, timer->interval_ms, timer->count);
for (int i = 0; i < timer->count; i++) {
usleep(timer->interval_ms * 1000); // 转换为微秒
printf("[Timer %d] Executing task #%d\n", timer->task_id, i + 1);
// 执行实际任务
if (timer->task_func) {
timer->task_func(timer->arg);
}
}
printf("[Timer %d] Completed\n", timer->task_id);
free(timer->arg);
free(timer);
}
// 示例定时任务:传感器数据采集
void sensor_data_collection(void *arg) {
int sensor_id = *(int *)arg;
int value = rand() % 100;
printf("[Sensor %d] Value: %d\n", sensor_id, value);
}
// 示例定时任务:心跳检测
void heartbeat_check(void *arg) {
int server_id = *(int *)arg;
printf("[Heartbeat] Server %d is alive\n", server_id);
}
// 模拟定时任务调度器
void simulate_timer_scheduler(void) {
printf("=== Timer Task Scheduler Simulation ===\n");
// 创建线程池:2个工作线程,最大20个任务
ThreadPool *pool = thread_pool_create(2, 20);
if (pool == NULL) {
fprintf(stderr, "Failed to create thread pool\n");
return;
}
// 创建定时任务
TimerTask *tasks[5];
// 任务1:每100ms采集传感器数据,执行10次
tasks[0] = (TimerTask *)malloc(sizeof(TimerTask));
tasks[0]->task_id = 1;
tasks[0]->interval_ms = 100;
tasks[0]->count = 10;
tasks[0]->task_func = sensor_data_collection;
tasks[0]->arg = malloc(sizeof(int));
*(int *)tasks[0]->arg = 1;
// 任务2:每200ms采集另一个传感器数据,执行5次
tasks[1] = (TimerTask *)malloc(sizeof(TimerTask));
tasks[1]->task_id = 2;
tasks[1]->interval_ms = 200;
tasks[1]->count = 5;
tasks[1]->task_func = sensor_data_collection;
tasks[1]->arg = malloc(sizeof(int));
*(int *)tasks[1]->arg = 2;
// 任务3:每500ms发送心跳,执行3次
tasks[2] = (TimerTask *)malloc(sizeof(TimerTask));
tasks[2]->task_id = 3;
tasks[2]->interval_ms = 500;
tasks[2]->count = 3;
tasks[2]->task_func = heartbeat_check;
tasks[2]->arg = malloc(sizeof(int));
*(int *)tasks[2]->arg = 1;
// 提交定时任务到线程池
for (int i = 0; i < 3; i++) {
if (thread_pool_submit(pool, timer_task_executor, tasks[i]) != 0) {
fprintf(stderr, "Failed to submit timer task %d\n", i + 1);
free(tasks[i]->arg);
free(tasks[i]);
} else {
printf("Timer task %d submitted\n", i + 1);
}
}
// 等待定时任务完成
sleep(5);
// 销毁线程池
thread_pool_destroy(pool);
}
int main() {
srand(time(NULL));
simulate_timer_scheduler();
return 0;
}
编译运行:
gcc -pthread -o timer_scheduler timer_scheduler.c
./timer_scheduler
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 线程数设置不合理 | 过多线程导致上下文切换开销 | 根据CPU核心数设置,通常为核心数的2倍 |
| 队列大小不合理 | 过小导致任务丢失,过大浪费内存 | 根据任务特点和内存限制设置 |
| 内存分配失败 | malloc失败导致创建失败 | 检查返回值,失败时清理资源 |
| 同步原语初始化失败 | mutex/cond初始化失败 | 检查返回值,失败时清理资源 |
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 任务参数内存泄漏 | 提交后忘记释放参数 | 任务执行完成后释放参数 |
| 空指针参数 | 传入NULL作为参数 | 检查参数有效性 |
| 任务函数为空 | function指针为NULL | 检查函数指针有效性 |
| 队列满时阻塞 | 提交任务时队列满 | 设置超时或使用非阻塞模式 |
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 未设置关闭标志 | 工作线程无法退出 | 先设置shutdown标志 |
| 未唤醒工作线程 | 工作线程在等待条件变量 | 使用broadcast唤醒所有线程 |
| 未等待线程退出 | 资源未完全释放 | 使用pthread_join等待所有线程 |
| 未清理剩余任务 | 任务内存泄漏 | 销毁时清理队列中的所有任务 |
// 错误示例1:任务参数内存泄漏
void bad_task(void *arg) {
char *data = (char *)arg;
printf("Data: %s\n", data);
// 错误:没有释放data
}
// 正确做法
void good_task(void *arg) {
char *data = (char *)arg;
printf("Data: %s\n", data);
free(data); // 释放参数
}
// 错误示例2:未检查线程池创建返回值
ThreadPool *pool = thread_pool_create(4, 100);
// 如果pool为NULL,后续操作会崩溃
// 正确做法
ThreadPool *pool = thread_pool_create(4, 100);
if (pool == NULL) {
fprintf(stderr, "Failed to create thread pool\n");
return 1;
}
// 错误示例3:销毁时未等待线程退出
pool->shutdown = 1;
free(pool->threads); // 线程可能还在运行
// 正确做法:先pthread_join,再释放内存
资源限制:
实时性考虑:
错误处理:
答:
答:
答:
not_empty:队列非空时唤醒工作线程not_full:队列未满时唤醒管理线程答:
1. 加锁
2. 检查队列是否为空且未关闭
- 是:等待条件变量(not_empty)
- 否:继续
3. 取出任务节点
4. 队列计数减1
5. 通知队列有空间(not_full)
6. 解锁
7. 执行任务函数
8. 释放任务内存
9. 返回步骤1
答:
答:
答:
答: