C++ 任务队列:实现、应用与优化

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

在 C++ 中使用任务队列:从入门到进阶



在现代 C++ 开发中,异步数据处理几乎无处不在。任务队列(task queues)是组织代码并行执行的关键工具之一。它们允许在线程之间分配工作,避免阻塞,并有效利用 CPU 资源。在本文中,我们将探讨如何在 C++ 中实现任务队列,研究 producer-consumer 模式,并学习构建一个简单的 thread pool。



1. 基于 std::queue 的基础队列



最简单的任务队列是一个容器,可以向其中添加元素(任务)并以 FIFO 顺序提取它们。在 C++ 中,标准库中的 std::queue 非常适合此目的。然而,在处理多线程时,普通队列是不安全的:来自不同线程的并发访问会导致数据竞争。



考虑一个使用互斥锁和条件变量实现同步队列的基本示例:



#include <queue>#include <mutex>#include <condition_variable>#include <functional>

class TaskQueue {public: using Task = std::function<void()>;

void push(Task task) { std::lock_guard<std::mutex> lock(mutex_); queue_.push(std::move(task)); cond_var_.notify_one(); }

Task pop() { std::unique_lock<std::mutex> lock(mutex_); cond_var_.wait(lock, [this]() { return !queue_.empty(); }); Task task = std::move(queue_.front()); queue_.pop(); return task; }

bool empty() const { std::lock_guard<std::mutex> lock(mutex_); return queue_.empty(); }

private: std::queue<Task> queue_; mutable std::mutex mutex_; std::condition_variable cond_var_;};


在这段代码中,push() 添加一个任务并通知一个等待的线程。pop() 会阻塞线程,直到队列变为非空。这种方法解决了同步问题,但如果不进行修改,它无法扩展到多个消费者。



2. Producer-Consumer 模式



经典的 producer-consumer(生产者-消费者)问题非常适合任务队列。一个或多个生产者线程生成任务,而消费者线程执行它们。正确管理队列大小以避免溢出或空闲非常重要。



多个消费者的示例:



#include <thread>#include <vector>#include <iostream>

void worker(TaskQueue& queue, int id) { while (true) { auto task = queue.pop(); if (!task) break; // 终止信号 std::cout << "Worker " << id << " executing task"; task(); }}

int main() { TaskQueue queue; std::vector<std::thread> workers;

// 启动 4 个消费者线程 for (int i = 0; i < 4; ++i) { workers.emplace_back(worker, std::ref(queue), i); }

// 生产者添加任务 for (int i = 0; i < 10; ++i) { queue.push([i]() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::cout << "Task " << i << " done"; }); }

// 终止信号(nullptr 任务) for (auto& w : workers) { queue.push(nullptr); }

for (auto& w : workers) { w.join(); } return 0;}


这里,每个消费者获取一个任务,执行它,然后等待下一个任务。终止信号(nullptr)停止循环。这种模式常用于服务器应用程序、事件处理器和游戏引擎中。



3. Thread Pool — 用于任务队列的线程池



Thread pool(线程池)是任务队列之上的一层抽象,它管理

博客

书籍推荐