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;
}

 

posted @ 2025-12-12 21:42  钟齐峰  阅读(6)  评论(0)    收藏  举报