C++11实现线程池

这是一个线程池实现,结合了多个异步编程示例。让我详细解释每个部分:

整体结构

代码展示了多种 C++11 异步编程技术的用法,最后实现了一个完整的线程池。

各部分详解

1. 第一部分:std::async 的基本用法

复制代码
void task(const char* name) {
    std::cout << name << " 开始执行,线程ID: "
        << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << name << " 完成" << std::endl;
}
  • 演示了 std::async的两种启动策略:

    • std::launch::async: 立即在新线程中执行

    • std::launch::deferred: 延迟执行(调用 get()时才执行)

2. 第二部分:std::future 获取结果

复制代码
std::future<int> result = std::async(std::launch::async, simpleTask);
int value = result.get();
  • 展示了如何通过 std::future::get()获取异步任务结果

  • 注意:get()只能调用一次

3. 第三部分:std::promise 和 std::future

复制代码
std::promise<double> prom;
auto fut = prom.get_future();
std::thread t(computeSqrt, std::move(prom), 9);
  • std::promise用于在线程间传递结果

  • 可以从 promise 获取 future

  • 可以在另一个线程中设置值或异常

4. 第四部分:std::shared_future

复制代码
std::shared_future<int> sharedFut = prom.get_future().share();
  • 多个线程可以共享同一个 future

  • get()可以多次调用

  • 通过 share()从普通 future 创建 shared_future

5. 第五部分:std::packaged_task

复制代码
std::packaged_task<int(int)> task([](int x) { return x * x; });
std::future<int> result = task.get_future();
std::thread worker(std::move(task), 5);
  • 包装可调用对象

  • 可以获取关联的 future

  • 可以传递给线程执行

6. 第六部分:任务队列和条件变量

复制代码
void taskRunner(std::queue<std::packaged_task<int()>>& taskqueue, ...) {
    while (true) {
        std::unique_lock<std::mutex> lock(task_mtx);
        cv.wait(lock, [&taskqueue] { return !taskqueue.empty(); });
        // 处理任务
    }
}
  • 使用 std::condition_variable实现线程间通信

  • 工作线程等待任务,有任务时被唤醒

  • 主线程添加任务到队列

7. 第七部分:并行计算示例(计算素数)

复制代码
futures.push_back(
    std::async(std::launch::async, countPrimes, start, end)
);
// 收集结果
int total1 = 0;
for (auto& fut : futures) {
    total1 += fut.get();
}
  • 将大任务拆分成多个子任务

  • 使用 std::async并行计算

  • 收集所有结果并汇总

8. 第八部分:完整的 ThreadPool 类

这是最重要的部分,实现了一个生产级别的线程池

核心设计
复制代码
class ThreadPool {
private:
    std::vector<std::thread> workers;           // 工作线程
    std::queue<std::function<void()>> tasks;    // 任务队列
    
    std::mutex queue_mutex;                     // 队列互斥锁
    std::condition_variable condition;          // 条件变量
    bool stop;                                   // 停止标志
};
关键方法
  1. 构造函数:创建指定数量的工作线程

  2. enqueue 方法:提交任务到线程池

  3. 析构函数:优雅关闭线程池

模板方法 enqueue
复制代码
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
    -> std::future<typename std::result_of<F(Args...)>::type> {
    // 1. 推导返回类型
    using return_type = typename std::result_of<F(Args...)>::type;
    
    // 2. 创建 packaged_task
    auto task = std::make_shared<std::packaged_task<return_type()>>(
        std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );
    
    // 3. 获取 future
    std::future<return_type> res = task->get_future();
    
    // 4. 将任务添加到队列
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        tasks.emplace([task]() { (*task)(); });
    }
    
    // 5. 通知一个等待的线程
    condition.notify_one();
    return res;
}
工作线程循环
复制代码
for (;;) {
    std::function<void()> task;
    
    {
        std::unique_lock<std::mutex> lock(this->queue_mutex);
        
        // 等待条件:线程池停止 或 队列不为空
        this->condition.wait(lock,
            [this] { return this->stop || !this->tasks.empty(); });
        
        // 线程池停止且队列为空 -> 退出
        if (this->stop && this->tasks.empty())
            return;
        
        task = std::move(this->tasks.front());
        this->tasks.pop();
    }
    
    task();  // 执行任务
}

9. 主函数测试

复制代码
int main() {
    const int MAX = 100000000;
    const int THREADS = 8;
    ThreadPool pool(8);  // 创建线程池
    
    std::vector<std::future<int>> futures;
    
    // 拆分任务并提交到线程池
    for (int i = 0; i < THREADS; ++i) {
        int start = i * chunk + 1;
        int end = (i == THREADS - 1) ? MAX : (i + 1) * chunk;
     
        futures.push_back(
            pool.enqueue(countPrimes, start, end)  // 提交任务
        );
    }
    
    // 收集结果
    int total1 = 0;
    for (auto& fut : futures) {
        total1 += fut.get();  // 阻塞等待结果
    }
    
    std::cout << "素数总数: " << total1 << std::endl;
    return 0;
}

关键特性总结

  1. 线程安全:使用互斥锁保护共享资源

  2. 任务队列:FIFO 顺序执行任务

  3. 条件变量:高效等待任务

  4. 优雅关闭:析构时等待所有任务完成

  5. 异常安全:任务异常不会影响线程池

  6. 通用接口:支持任意可调用对象

  7. 返回结果 :通过 std::future获取任务结果

使用场景

  • 需要大量并发执行的小任务

  • 避免频繁创建/销毁线程的开销

  • 控制并发线程数量

  • 实现生产者-消费者模式

这个线程池实现是生产可用的,包含了异常处理、资源管理和优雅关闭等关键特性。

相关推荐
若水不如远方5 小时前
分布式一致性(三):共识的黎明——Quorum 机制与 Basic Paxos
分布式·后端·算法
无水先生5 小时前
python函数的参数管理(01)*args和**kwargs
开发语言·python
py小王子5 小时前
dy评论数据爬取实战:基于DrissionPage的自动化采集方案
大数据·开发语言·python·毕业设计
only-qi5 小时前
leetcode24两两交换链表中的节点 快慢指针实现
数据结构·算法·链表
小陶的学习笔记5 小时前
python~基础
开发语言·python·学习
多恩Stone5 小时前
【3D AICG 系列-9】Trellis2 推理流程图超详细介绍
人工智能·python·算法·3d·aigc·流程图
sin_hielo5 小时前
leetcode 110
数据结构·算法·leetcode
整得咔咔响5 小时前
贝尔曼最优公式(BOE)
人工智能·算法·机器学习
日拱一卒——功不唐捐5 小时前
字符串匹配:暴力法和KMP算法(C语言)
c语言·算法