引言:为什么在 C++ 中需要任务队列?
在现代编程中,尤其是在处理多线程应用程序时,经常需要按任务到达的顺序组织执行。任务队列是一种基础模式,它能够有效地在线程之间分配工作、处理 Web 服务器请求、管理后台进程并避免竞态条件。
在 C++ 中,标准库提供了强大的容器 std::queue,非常适合实现任务队列。然而,在实际应用中,不仅需要存储元素,还需要在线程之间安全地传递它们、处理错误并管理任务的生命周期。在本文中,我们将从零开始讲解如何使用现代 C++ 特性(C++11 及更高版本)创建任务队列。
我们将讨论:
std::queue的基本操作- 线程安全的任务队列
- 线程池的实现
- 优先级队列
1. 使用 std::queue 的基本任务队列
从一个简单的例子开始。std::queue 是一个容器适配器,遵循先进先出(FIFO)原则。它提供了 push()、pop()、front() 和 empty() 方法。
以下是如何组织一个任务队列,其中每个任务都是一个函数(或可调用对象):
#include <iostream>#include <queue>#include <functional>
int main() { // 任务队列,每个任务都是 std::function<void()> std::queue<std::function<void()>> taskQueue;
// 添加任务 taskQueue.push([]() { std::cout << "任务 1 已完成"; }); taskQueue.push([]() { std::cout << "任务 2 已完成"; }); taskQueue.push([]() { std::cout << "任务 3 已完成"; });
// 处理队列 while (!taskQueue.empty()) { auto task = taskQueue.front(); task(); // 执行任务 taskQueue.pop(); // 移除已完成的任务 }
return 0;}这段代码可以工作,但仅限于单线程模式。如果多个线程同时添加或取出任务,就会产生竞态条件。对于多线程,需要同步机制。
2. 线程安全的任务队列
为了使队列对多线程访问安全,我们使用互斥锁(std::mutex)和条件变量(std::condition_variable)。这是经典的生产者-消费者模式。
线程安全队列的实现:
#include <queue>#include <mutex>#include <condition_variable>#include <functional>#include <thread>
class ThreadSafeQueue {private: std::queue<std::function<void()>> queue_; std::mutex mutex_; std::condition_variable cond_; bool stop_ = false;
public: void push(std::function<void()> task) { std::lock_guard<std::mutex> lock(mutex_); queue_.push(task); cond_.notify_one(); // 通知一个等待的线程 }
std::function<void()> pop() { std::unique_lock<std::mutex> lock(mutex_); cond_.wait(lock, [this]() { return !queue_.empty() || stop_; }); if (stop_ && queue_.empty()) { return nullptr; // 停止信号 } auto task = queue_.front(); queue_.pop(); return task; }
void stop() { std::lock_guard<std::mutex> lock(mutex_); stop_ = true; cond_.notify_all(); // 唤醒所有线程以完成 }};关键点:
std::lock_gu