C++03线程池:基于POSIX线程库的实现

C++03线程池:基于POSIX线程库的实现

什么是线程池?

线程池是一种并发编程模式,它预先创建一定数量的工作线程,这些线程会循环等待并执行提交的任务。这种模式避免了频繁创建和销毁线程带来的性能开销,是处理大量并发任务的高效解决方案。

在C++11标准之前,C++语言本身并没有提供线程库,因此线程池的实现需要依赖操作系统提供的线程接口。本文将基于POSIX线程库(pthread)实现一个兼容C++03标准的线程池。

线程池的核心优势

  1. 减少线程创建销毁开销:线程的创建和销毁涉及内核态操作,成本较高。线程池通过复用已创建的线程,显著减少这些操作。

  2. 控制资源消耗:限制并发线程的最大数量,避免因创建过多线程导致的系统资源耗尽和调度开销增加。

  3. 提高任务响应速度:线程预先创建并处于就绪状态,任务提交后可立即执行,无需等待线程创建。

  4. 简化并发编程:封装了线程管理和同步细节,开发者只需关注任务逻辑。

线程池的核心组件

一个典型的线程池包含以下核心组件:

  • 工作线程:预先创建的线程,负责从任务队列中获取并执行任务
  • 任务队列:存储待执行任务的数据结构,通常为先进先出(FIFO)队列
  • 同步机制:确保多线程安全访问任务队列的互斥锁和条件变量
  • 线程管理接口:用于创建线程池、提交任务、调整线程数量和销毁线程池

C++03线程池实现

头文件(thread_pool.h)

#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include <vector>
#include <queue>
#include <pthread.h>
#include <cstddef>
#include <stdexcept>
#include <cassert>

// 任务基类,用于类型擦除
class Task {
public:
    virtual ~Task() {}
    virtual void execute() = 0;
};

// 具体任务模板类
template<typename Result>
class ResultTask : public Task {
public:
    // 函数指针类型定义
    typedef Result (*Function)();

    ResultTask(Function func) : func_(func), completed_(false) {}

    void execute() {
        result_ = func_();
        completed_ = true;
    }

    Result get_result() {
        // 简单的忙等待(实际应用可考虑添加超时机制)
        while (!completed_) {
            // 让出CPU时间片
            sched_yield();
        }
        return result_;
    }

private:
    Function func_;       // 任务函数
    Result result_;       // 任务结果
    bool completed_;      // 完成标志
};

// 无返回值任务特化
template<>
class ResultTask<void> : public Task {
public:
    typedef void (*Function)();

    ResultTask(Function func) : func_(func), completed_(false) {}

    void execute() {
        func_();
        completed_ = true;
    }

    void get_result() {
        while (!completed_) {
            sched_yield();
        }
    }

private:
    Function func_;
    bool completed_;
};

// 线程池类
class ThreadPool {
public:
    // 构造函数:指定线程数量
    explicit ThreadPool(size_t num_threads) 
        : stop_(false), num_threads_(num_threads) {
        // 初始化互斥锁
        if (pthread_mutex_init(&mutex_, NULL) != 0) {
            throw std::runtime_error("Failed to initialize mutex");
        }
        
        // 初始化条件变量
        if (pthread_cond_init(&cond_, NULL) != 0) {
            pthread_mutex_destroy(&mutex_);
            throw std::runtime_error("Failed to initialize condition variable");
        }
        
        // 创建工作线程
        threads_.resize(num_threads_);
        for (size_t i = 0; i < num_threads_; ++i) {
            if (pthread_create(&threads_[i], NULL, worker_thread, this) != 0) {
                // 清理已创建的线程
                stop_ = true;
                pthread_cond_broadcast(&cond_);
                
                for (size_t j = 0; j < i; ++j) {
                    pthread_join(threads_[j], NULL);
                }
                
                pthread_mutex_destroy(&mutex_);
                pthread_cond_destroy(&cond_);
                throw std::runtime_error("Failed to create thread");
            }
        }
    }

    // 析构函数
    ~ThreadPool() {
        // 停止所有线程
        pthread_mutex_lock(&mutex_);
        stop_ = true;
        pthread_cond_broadcast(&cond_);  // 唤醒所有等待的线程
        pthread_mutex_unlock(&mutex_);
        
        // 等待所有线程结束
        for (size_t i = 0; i < threads_.size(); ++i) {
            pthread_join(threads_[i], NULL);
        }
        
        // 清理剩余任务
        while (!tasks_.empty()) {
            Task* task = tasks_.front();
            tasks_.pop();
            delete task;
        }
        
        // 销毁同步对象
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

    // 禁止拷贝
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

    // 提交有返回值的任务
    template<typename Result>
    Result submit(Result (*func)()) {
        ResultTask<Result>* task = new ResultTask<Result>(func);
        
        pthread_mutex_lock(&mutex_);
        tasks_.push(task);
        pthread_cond_signal(&cond_);  // 唤醒一个工作线程
        pthread_mutex_unlock(&mutex_);
        
        Result result = task->get_result();
        delete task;
        return result;
    }

    // 提交无返回值的任务
    void submit(void (*func)()) {
        ResultTask<void>* task = new ResultTask<void>(func);
        
        pthread_mutex_lock(&mutex_);
        tasks_.push(task);
        pthread_cond_signal(&cond_);
        pthread_mutex_unlock(&mutex_);
        
        task->get_result();  // 等待任务完成
        delete task;
    }

    // 动态调整线程数量
    void resize(size_t new_num_threads) {
        if (new_num_threads == num_threads_) return;
        
        pthread_mutex_lock(&mutex_);
        size_t old_num = num_threads_;
        num_threads_ = new_num_threads;
        
        // 增加线程
        if (new_num_threads > old_num) {
            threads_.resize(new_num_threads);
            for (size_t i = old_num; i < new_num_threads; ++i) {
                if (pthread_create(&threads_[i], NULL, worker_thread, this) != 0) {
                    num_threads_ = i;
                    pthread_mutex_unlock(&mutex_);
                    throw std::runtime_error("Failed to resize thread pool");
                }
            }
        }
        pthread_mutex_unlock(&mutex_);
        
        // 减少线程
        if (new_num_threads < old_num) {
            // 唤醒足够的线程让它们退出
            for (size_t i = new_num_threads; i < old_num; ++i) {
                pthread_cond_signal(&cond_);
            }
            
            // 等待多余的线程退出
            for (size_t i = new_num_threads; i < old_num; ++i) {
                pthread_join(threads_[i], NULL);
            }
            
            pthread_mutex_lock(&mutex_);
            threads_.resize(new_num_threads);
            pthread_mutex_unlock(&mutex_);
        }
    }

    // 获取当前线程数量
    size_t thread_count() const {
        return num_threads_;
    }

private:
    // 工作线程函数(静态成员函数作为pthread入口)
    static void* worker_thread(void* arg) {
        ThreadPool* pool = static_cast<ThreadPool*>(arg);
        pool->process_tasks();
        return NULL;
    }

    // 线程处理任务的主循环
    void process_tasks() {
        while (true) {
            pthread_mutex_lock(&mutex_);
            
            // 等待任务或停止信号
            while (!stop_ && tasks_.empty()) {
                pthread_cond_wait(&cond_, &mutex_);
            }
            
            // 检查是否需要退出
            if (stop_ || threads_.size() > num_threads_) {
                pthread_mutex_unlock(&mutex_);
                break;
            }
            
            // 取出任务
            Task* task = tasks_.front();
            tasks_.pop();
            pthread_mutex_unlock(&mutex_);
            
            // 执行任务
            try {
                task->execute();
            } catch (const std::exception& e) {
                // 简单处理异常,实际应用可根据需要扩展
                fprintf(stderr, "Task execution error: %s\n", e.what());
            } catch (...) {
                fprintf(stderr, "Unknown task execution error\n");
            }
        }
    }

    std::vector<pthread_t> threads_;  // 工作线程数组
    std::queue<Task*> tasks_;         // 任务队列
    pthread_mutex_t mutex_;           // 保护任务队列的互斥锁
    pthread_cond_t cond_;             // 条件变量,用于通知线程有新任务
    bool stop_;                       // 线程池停止标志
    size_t num_threads_;              // 当前线程数量
};

#endif // THREAD_POOL_H

使用示例(main.cpp)

#include "thread_pool.h"
#include <iostream>
#include <cstdio>
#include <ctime>
#include <unistd.h>

// 示例任务1:计算平方
int calculate_square(int x) {
    // 模拟耗时操作
    usleep(10000);  // 10毫秒
    return x * x;
}

// 示例任务2:打印消息
void print_message(const char* msg) {
    usleep(5000);   // 5毫秒
    printf("Message: %s\n", msg);
}

// 包装函数,用于适配线程池的函数指针要求
int square_wrapper() {
    static int x = 0;
    int result = calculate_square(x);
    x = (x + 1) % 10;  // 循环计算0-9的平方
    return result;
}

// 打印消息的包装函数
void message_wrapper() {
    static int count = 0;
    char msg[128];
    sprintf(msg, "Task %d completed", count++);
    print_message(msg);
}

int main() {
    try {
        // 创建包含4个线程的线程池
        ThreadPool pool(4);
        printf("Initial thread count: %zu\n", pool.thread_count());
        
        // 提交10个计算平方的任务
        printf("\nCalculating squares:\n");
        for (int i = 0; i < 10; ++i) {
            int result = pool.submit(square_wrapper);
            printf("%d ", result);
        }
        printf("\n");
        
        // 调整线程数量为6
        pool.resize(6);
        printf("\nResized thread count: %zu\n", pool.thread_count());
        
        // 提交一批打印任务
        printf("\nPrinting messages:\n");
        for (int i = 0; i < 8; ++i) {
            pool.submit(message_wrapper);
        }
        
        // 再次调整线程数量为2
        pool.resize(2);
        printf("\nFinal thread count: %zu\n", pool.thread_count());
        
    } catch (const std::exception& e) {
        fprintf(stderr, "Error: %s\n", e.what());
        return 1;
    }
    
    return 0;
}

线程池工作原理

  1. 初始化阶段

    • 创建指定数量的工作线程
    • 初始化互斥锁和条件变量用于同步
    • 工作线程进入等待状态,等待新任务
  2. 任务提交阶段

    • 将任务封装成Task对象
    • 加锁后将任务放入任务队列
    • 发送信号唤醒一个等待的工作线程
  3. 任务执行阶段

    • 工作线程被唤醒,从队列中取出任务
    • 解锁后执行任务
    • 任务完成后,线程回到等待状态
  4. 动态调整阶段

    • 增加线程:直接创建新的工作线程
    • 减少线程:唤醒多余线程并让它们退出
  5. 销毁阶段

    • 设置停止标志并唤醒所有线程
    • 等待所有线程完成当前任务并退出
    • 清理剩余任务和同步对象

适用场景

  • 服务器开发:处理大量并发请求(如Web服务器、数据库服务器)
  • 批量数据处理:图像转换、数据分析等可并行的计算任务
  • 异步IO操作:网络请求、文件读写等IO密集型任务
  • 实时系统:需要控制线程数量和资源使用的嵌入式系统

编译与使用

使用GCC编译时需要指定C++03标准并链接pthread库:

g++ -std=c++03 main.cpp -o thread_pool -lpthread

这个实现虽然没有C++11及以上版本的线程池简洁,但在不支持现代C++标准的环境中仍然是一个可靠的多线程任务处理方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bkspiderx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值