Safe Queue

发布于 1 个月前·
1 人看过
·
约 3 分钟
·89 行代码
#pragma once
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>

template <typename T>
class SafeQueue {
private:
    std::queue<T> m_queue;
    mutable std::mutex m_mutex;

    // 两个条件变量实现“有界队列”
    std::condition_variable m_cond_not_empty;  // 队列不空:通知消费者可以取了
    std::condition_variable m_cond_not_full;   // 队列不满:通知生产者可以放了

    size_t m_max_size;  // 队列最大容量

public:
    // 构造函数:默认容量设为 1000
    // 如果你设为 4,就能很明显观察到生产者被阻塞的现象
    SafeQueue(size_t max_size = 1000) : m_max_size(max_size) {}

    // 禁止拷贝和移动(资源管理类的标准做法)
    SafeQueue(const SafeQueue &) = delete;
    SafeQueue &operator=(const SafeQueue &) = delete;
    SafeQueue(SafeQueue &&) = delete;
    SafeQueue &operator=(SafeQueue &&) = delete;

    ~SafeQueue() {}

    // 1. 生产者:入队 (带阻塞流控)
    // 如果队列满了,生产者会在这里等待,直到有空位
    void push(T new_value) {
        {
            std::unique_lock<std::mutex> lock(m_mutex);

            // 只要队列满了,就在这里阻塞
            m_cond_not_full.wait(lock, [this] { return m_queue.size() < m_max_size; });

            m_queue.push(std::move(new_value));
        }  // 离开作用域自动解锁

        // 通知消费者
        m_cond_not_empty.notify_one();
    }

    // 2. 消费者:阻塞出队
    // 如果队列空了,消费者会在这里等待
    void wait_pop(T &value) {
        {
            std::unique_lock<std::mutex> lock(m_mutex);

            // 等待“队列不空”
            m_cond_not_empty.wait(lock, [this] { return !m_queue.empty(); });

            value = std::move(m_queue.front());
            m_queue.pop();

            // 既然拿走了一个,肯定有空位了,通知生产者可以继续生产了
            m_cond_not_full.notify_one();

        }  // 自动解锁
    }

    // 3. 消费者:非阻塞出队 (可选接口)
    bool try_pop(T &value) {
        std::lock_guard<std::mutex> lock(m_mutex);
        if (m_queue.empty()) return false;

        value = std::move(m_queue.front());
        m_queue.pop();

        // 同样通知生产者
        m_cond_not_full.notify_one();
        return true;
    }

    // 4. 查询状态
    bool empty() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_queue.empty();
    }

    size_t size() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_queue.size();
    }
};
snippet
cpp
$ cd ..