C++队列解决生产者-消费者模型失衡问题
C++队列解决生产者-消费者模型失衡问题
在C++程序中,生产速度远快于消费速度时,本质问题是生产者-消费者模型失衡。典型后果包括:队列暴涨、延迟增加、内存占用失控、甚至阻塞或丢失数据。结合实际工程常见手段。
一、优先从架构上解决
如果任务是可并行的,最直接有效的方式是增加消费者数量(多消费线程)
std::vector<std::thread> consumers; for (int i = 0; i < N; ++i) { consumers.emplace_back([&] { while (true) { Task t; if (queue.pop(t)) { process(t); } } }); }
二、实现层面上,如果消费者多,建议换成线程安全队列(更高性能)
例如:
Boost lock-free queue
提高吞吐:
boost::lockfree::queue<PDFType> queue(1024); PDFType data; if (queue.pop(data)) { process(data); }
moodycamel::ConcurrentQueue
工业生产、高速实时系统常用:
moodycamel::ConcurrentQueue<PDFType> queue; PDFType data; if (queue.try_dequeue(data)) { process(data); }
当然也可以使用mutex + cv模式
- 比如实现一个完成可复用、工业级、线程安全、支持多生产者多消费者的C++20队列类。特点:
- 支持多个生产者线程
- 支持多个消费者线程
- 使用mutex+condition_variable,无数据竞争
- 支持阻塞pop,超时pop
- 支持关闭队列(优雅退出)
- 处理耗时任务时不会阻塞队列
- 工业场景稳定可靠
ThreadSafeQueue.hpp(完整实现):
#pragma once #include <queue> #include <mutex> #include <condition_variable> #include <optional> #include <chrono> template <typename T> class ThreadSafeQueue { public: ThreadSafeQueue() : m_closed(false) {} // 禁止拷贝,允许移动 ThreadSafeQueue(const ThreadSafeQueue&) = delete; ThreadSafeQueue& operator=(const ThreadSafeQueue&) = delete; // ---- 生产 ---- bool push(const T& value) { { std::unique_lock<std::mutex> lock(m_mutex); if (m_closed) return false; m_queue.push(value); } m_cv.notify_one(); return true; } bool push(T&& value) { { std::unique_lock<std::mutex> lock(m_mutex); if (m_closed) return false; m_queue.push(std::move(value)); } m_cv.notify_one(); return true; } // ---- 消费(阻塞等待)---- std::optional<T> pop() { std::unique_lock<std::mutex> lock(m_mutex); m_cv.wait(lock, [&] { return m_closed || !m_queue.empty(); }); if (m_queue.empty()) return std::nullopt; // 队列关闭了 T value = std::move(m_queue.front()); m_queue.pop(); return value; } // ---- 消费(带 timeout)---- template <class Rep, class Period> std::optional<T> pop_for(const std::chrono::duration<Rep, Period>& timeout) { std::unique_lock<std::mutex> lock(m_mutex); if (!m_cv.wait_for(lock, timeout, [&] { return m_closed || !m_queue.empty(); })) { return std::nullopt; // 超时 } if (m_queue.empty()) return std::nullopt; // 关闭 T value = std::move(m_queue.front()); m_queue.pop(); return value; } // ---- 关闭队列(通知所有消费者退出)---- void close() { { std::unique_lock<std::mutex> lock(m_mutex); m_closed = true; } m_cv.notify_all(); } bool closed() const { std::unique_lock<std::mutex> lock(m_mutex); return m_closed; } size_t size() const { std::unique_lock<std::mutex> lock(m_mutex); return m_queue.size(); } private: mutable std::mutex m_mutex; std::condition_variable m_cv; std::queue<T> m_queue; bool m_closed; };
使用示例:多生产者 + 多消费者
ThreadSafeQueue<int> queue; std::atomic<bool> running = true; // ---- 消费者线程 ---- void consumer(int id) { while (true) { auto item = queue.pop(); // 阻塞等待 if (!item.has_value()) // 队列关闭 break; int value = *item; std::cout << "Consumer " << id << " got " << value << "\n"; // 模拟处理耗时任务 std::this_thread::sleep_for(std::chrono::milliseconds(20)); } } // ---- 生产者线程 ---- void producer(int id) { for (int i = 0; i < 20; i++) { queue.push(i + id * 1000); std::this_thread::sleep_for(std::chrono::milliseconds(5)); } } int main() { std::thread p1(producer, 1); std::thread p2(producer, 2); std::thread c1(consumer, 1); std::thread c2(consumer, 2); std::thread c3(consumer, 3); p1.join(); p2.join(); // 生产完毕,关闭队列 queue.close(); c1.join(); c2.join(); c3.join(); return 0; }
浙公网安备 33010602011771号