答案是使用互斥锁、条件变量和队列实现线程安全的阻塞队列,通过加锁和条件等待确保push和pop操作在多线程下的正确性,支持阻塞与唤醒机制。

在C++中实现一个线程安全的阻塞队列,核心是结合互斥锁(std::mutex)、条件变量(std::condition_variable)和一个底层容器(如 std::queue)。阻塞队列的特点是:当队列为空时,出队操作会阻塞;当队列满时(如果有容量限制),入队操作也会阻塞。
基本设计思路
阻塞队列需要满足多线程环境下安全地进行 push 和 pop 操作。主要依赖以下机制:
- std::mutex:保护共享数据(队列),防止多个线程同时访问导致数据竞争。
- std::condition_variable:用于线程间通信,使等待的线程在条件满足时被唤醒。
- std::queue:作为内部存储结构。
- 可选的固定容量限制:实现有界队列,提高资源控制能力。
关键操作逻辑
两个核心成员函数是 push 和 pop,它们都需要加锁,并在特定条件下等待。
push(value) 操作流程:
立即学习“C++免费学习笔记(深入)”;
- 获取互斥锁。
- 如果队列已满(设置了最大容量),则等待 not_full 条件变量。
- 将元素加入队列。
- 通知可能正在等待的 pop 线程(通过 notify_one 或 notify_all)。
- 释放锁。
pop() -> value 操作流程:
- 获取互斥锁。
- 如果队列为空,等待 not_empty 条件变量。
- 取出队首元素并移除。
- 通知可能正在等待的 push 线程。
- 返回取出的值。
C++ 示例代码
下面是一个简单的线程安全阻塞队列实现:
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
template <typename T>
class BlockingQueue {
private:
std::queue<T> queue_;
std::mutex mtx_;
std::condition_variable not_empty_;
std::condition_variable not_full_;
size_t max_size_;
public:
explicit BlockingQueue(size_t max_size = SIZE_MAX) : max_size_(max_size) {}
void push(const T& item) {
std::unique_lock<std::mutex> lock(mtx_);
not_full_.wait(lock, [this] { return queue_.size() < max_size_; });
queue_.push(item);
not_empty_.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(mtx_);
not_empty_.wait(lock, [this] { return !queue_.empty(); });
T item = std::move(queue_.front());
queue_.pop();
not_full_.notify_one();
return item;
}
bool empty() const {
std::lock_guard<std::mutex> lock(mtx_);
return queue_.empty();
}
size_t size() const {
std::lock_guard<std::mutex> lock(mtx_);
return queue_.size();
}
};
使用示例:
BlockingQueue<int> bq(5);
std::thread producer([&]() {
for (int i = 0; i < 10; ++i) {
bq.push(i);
std::cout << "Produced: " << i << "\n";
}
});
std::thread consumer([&]() {
for (int i = 0; i < 10; ++i) {
int val = bq.pop();
std::cout << "Consumed: " << val << "\n";
}
});
producer.join();
consumer.join();
注意事项与优化点
实际使用中还需考虑一些细节:
- 支持移动语义:使用 T&& 重载 push 可提升性能。
- 超时操作:提供 try_push / try_pop 带超时版本,使用 wait_for 或 wait_until。
- 关闭机制:添加 shutdown 标志,使等待线程能优雅退出。
- notify_all vs notify_one:notify_one 更高效,适用于一对一生产消费;notify_all 适合广播场景。











