13. 线程池模式.md 28 KB

13 线程池模式

13.1 完整概念讲解

13.1.1 线程池概念

线程池(Thread Pool) 是一种多线程处理模式,预先创建一定数量的线程,将任务放入队列中,由空闲线程从队列中取出任务执行。

核心优势:

  • 减少创建/销毁开销:线程预先创建,避免频繁的线程创建和销毁
  • 提高响应速度:任务到达时立即有线程处理,无需等待线程创建
  • 控制并发数量:限制同时运行的线程数,避免系统过载
  • 统一资源管理:集中管理线程资源,便于监控和调试

线程池工作流程:

任务提交 → 任务队列 → 工作线程取任务 → 执行任务 → 返回等待新任务

13.1.2 线程池架构

三大核心组件:

┌─────────────────────────────────────────────────────────┐
│                     线程池管理器                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │  工作线程1   │  │  工作线程2   │  │  工作线程N   │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
│         │               │               │               │
│         └───────────────┼───────────────┘               │
│                         │                               │
│                   ┌─────┴─────┐                         │
│                   │  任务队列  │                         │
│                   └───────────┘                         │
│                                                          │
│  ┌─────────────────────────────────────────────────┐   │
│  │              任务结构体(函数指针+参数)            │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

组件职责:

组件 职责 关键技术
任务结构体 封装任务函数和参数 函数指针、void*参数
任务队列 存储待执行的任务 链表或数组实现
工作线程 从队列取任务并执行 while循环、条件变量
管理线程 监控和管理线程池 动态调整线程数、销毁线程池

13.1.3 任务结构体设计

// 任务结构体:封装任务函数和参数
typedef struct {
    void (*function)(void *arg);  // 任务函数指针
    void *arg;                     // 任务参数
} Task;

设计要点:

  • 函数指针:指向要执行的任务函数
  • 参数指针:使用void*实现通用参数传递
  • 内存管理:任务结构体需要动态分配内存

13.1.4 任务队列设计

链表实现(推荐):

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 数组:

特性 链表 数组
动态扩展 支持 不支持
内存开销 额外指针开销 固定大小
缓存友好性 较差 较好
实现复杂度 较高 较低

13.1.5 线程安全的入队/出队

互斥锁 + 条件变量实现:

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;
}

13.1.6 工作线程循环

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;
}

13.1.7 嵌入式应用场景

网络请求处理:

  • Web服务器处理HTTP请求
  • TCP服务器处理客户端连接
  • UDP服务器处理数据包

定时任务调度:

  • 定时器回调执行
  • 周期性任务(如传感器数据采集)
  • 超时检测和处理

后台任务处理:

  • 日志写入
  • 数据同步
  • 邮件发送

13.2 核心API/语法

13.2.1 线程池创建函数

#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);

13.2.2 任务提交函数

// 向线程池提交任务
int thread_pool_submit(ThreadPool *pool, void (*function)(void *arg), void *arg);

13.2.3 线程池销毁函数

// 销毁线程池
int thread_pool_destroy(ThreadPool *pool);

13.2.4 互斥锁和条件变量函数

// 互斥锁
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);

13.3 代码示例

13.3.1 完整线程池实现

#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;
}

13.3.2 使用示例:任务执行

#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;
}

13.3.3 编译完整示例

将线程池实现和使用示例保存为threadpool_demo.c,然后编译运行:

gcc -pthread -o threadpool_demo threadpool_demo.c
./threadpool_demo

13.3.4 嵌入式场景:网络请求处理

#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

13.3.5 嵌入式场景:定时任务调度

#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

13.4 注意事项与易错点

13.4.1 线程池创建注意事项

问题 描述 解决方案
线程数设置不合理 过多线程导致上下文切换开销 根据CPU核心数设置,通常为核心数的2倍
队列大小不合理 过小导致任务丢失,过大浪费内存 根据任务特点和内存限制设置
内存分配失败 malloc失败导致创建失败 检查返回值,失败时清理资源
同步原语初始化失败 mutex/cond初始化失败 检查返回值,失败时清理资源

13.4.2 任务提交注意事项

问题 描述 解决方案
任务参数内存泄漏 提交后忘记释放参数 任务执行完成后释放参数
空指针参数 传入NULL作为参数 检查参数有效性
任务函数为空 function指针为NULL 检查函数指针有效性
队列满时阻塞 提交任务时队列满 设置超时或使用非阻塞模式

13.4.3 线程池销毁注意事项

问题 描述 解决方案
未设置关闭标志 工作线程无法退出 先设置shutdown标志
未唤醒工作线程 工作线程在等待条件变量 使用broadcast唤醒所有线程
未等待线程退出 资源未完全释放 使用pthread_join等待所有线程
未清理剩余任务 任务内存泄漏 销毁时清理队列中的所有任务

13.4.4 常见错误代码示例

// 错误示例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,再释放内存

13.4.5 嵌入式场景注意事项

资源限制:

  • 嵌入式系统内存有限,线程池大小受限
  • 线程栈大小需要根据任务调整
  • 避免使用动态内存分配(如可能)

实时性考虑:

  • 线程池不适合硬实时任务
  • 任务执行时间不确定
  • 需要评估最坏情况下的延迟

错误处理:

  • 任务执行失败需要重试机制
  • 线程异常退出需要重新创建
  • 需要健康监控和故障恢复

13.5 面试要点

Q1: 什么是线程池?为什么需要线程池?

答:

  • 定义:线程池是一种多线程处理模式,预先创建一定数量的线程,将任务放入队列中执行
  • 优势
    1. 减少线程创建/销毁开销
    2. 提高响应速度(任务到达立即处理)
    3. 控制并发数量,避免系统过载
    4. 统一资源管理,便于监控

Q2: 线程池的核心组件有哪些?

答:

  • 任务结构体:封装任务函数和参数(函数指针+void*参数)
  • 任务队列:存储待执行的任务(链表或数组实现)
  • 工作线程:从队列取任务并执行(while循环+条件变量)
  • 管理线程:监控和管理线程池(动态调整、销毁)

Q3: 如何实现线程安全的任务队列?

答:

  • 使用互斥锁保护队列的读写操作
  • 使用条件变量实现线程同步:
    • not_empty:队列非空时唤醒工作线程
    • not_full:队列未满时唤醒管理线程
  • 入队/出队操作需要在加锁状态下进行

Q4: 工作线程的工作流程是什么?

答:

1. 加锁
2. 检查队列是否为空且未关闭
   - 是:等待条件变量(not_empty)
   - 否:继续
3. 取出任务节点
4. 队列计数减1
5. 通知队列有空间(not_full)
6. 解锁
7. 执行任务函数
8. 释放任务内存
9. 返回步骤1

Q5: 如何处理线程池中的任务失败?

答:

  • 任务层面:在任务函数中添加错误处理和重试逻辑
  • 线程层面:工作线程捕获异常,防止线程退出
  • 监控层面:记录失败任务,通知管理员
  • 超时机制:为任务设置超时,避免长时间阻塞

Q6: 线程池在嵌入式系统中的应用场景有哪些?

答:

  • 网络请求处理:Web服务器、TCP/UDP服务器
  • 定时任务调度:传感器数据采集、心跳检测
  • 后台任务处理:日志写入、数据同步
  • 多协议处理:同时处理多种通信协议
  • 资源受限场景:避免频繁创建/销毁线程

Q7: 如何优化线程池性能?

答:

  • 线程数优化:根据CPU核心数和任务类型设置
    • CPU密集型:核心数+1
    • IO密集型:核心数×2
  • 队列优化:根据任务特点选择链表或数组
  • 任务粒度:避免任务过大或过小
  • 缓存友好:减少缓存未命中
  • 减少锁竞争:使用无锁队列(高级优化)

Q8: 线程池的常见设计模式有哪些?

答:

  • 固定大小线程池:线程数固定,任务排队执行
  • 可缓存线程池:任务多时创建新线程,空闲时回收
  • 定时线程池:支持定时和周期性任务
  • 单线程线程池:单个工作线程,保证任务顺序执行
  • 工作窃取线程池:空闲线程从其他线程队列窃取任务(ForkJoinPool)