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