阻塞队列通过互斥锁和条件变量实现线程安全的生产者-消费者模型,支持固定容量下的阻塞插入与提取,适用于任务调度与线程间通信。

在C++多线程编程中,阻塞队列是线程间通信的常用工具。它允许一个或多个生产者线程向队列添加数据,同时一个或多个消费者线程从队列获取数据。当队列为空时,消费者线程会被阻塞,直到有新数据进入;当队列满时(如果是有界队列),生产者线程也会被阻塞,直到有空间可用。
借助 std::queue、std::mutex、std::condition_variable 和 std::unique_lock,可以轻松实现一个线程安全的阻塞队列。
示例代码:
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
template<typename T>
class BlockingQueue {
private:
std::queue<T> data_queue;
mutable std::mutex mtx;
std::condition_variable not_empty;
std::condition_variable not_full;
size_t max_size;
public:
explicit BlockingQueue(size_t max_sz = 1000) : max_size(max_sz) {}
void push(const T& item) {
std::unique_lock<std::mutex> lock(mtx);
not_full.wait(lock, [this] { return data_queue.size() < max_size; });
data_queue.push(item);
not_empty.notify_one();
}
void pop(T& item) {
std::unique_lock<std::mutex> lock(mtx);
not_empty.wait(lock, [this] { return !data_queue.empty(); });
item = data_queue.front();
data_queue.pop();
not_full.notify_one();
}
bool try_pop(T& item) {
std::unique_lock<std::mutex> lock(mtx);
if (data_queue.empty()) {
return false;
}
item = data_queue.front();
data_queue.pop();
not_full.notify_one();
return true;
}
bool empty() const {
std::lock_guard<std::mutex> lock(mtx);
return data_queue.empty();
}
size_t size() const {
std::lock_guard<std::mutex> lock(mtx);
return data_queue.size();
}
};
阻塞队列常用于生产者-消费者模型。以下是一个简单示例,展示两个线程如何通过阻塞队列通信。
int main() {
BlockingQueue<int> queue(5); // 最多容纳5个元素
std::thread producer([&]() {
for (int i = 0; i < 10; ++i) {
queue.push(i);
std::cout << "生产: " << i << "\n";
}
});
std::thread consumer([&]() {
for (int i = 0; i < 10; ++i) {
int value;
queue.pop(value);
std::cout << "消费: " << value << "\n";
}
});
producer.join();
consumer.join();
return 0;
}
实现阻塞队列时需要注意几个核心机制:
Whimsical
Whi
msical推出的AI思维导图工具
182
查看详情
如果需要无界队列,可以去掉 max_size 限制和 not_full 条件变量,只保留 not_empty 即可。
阻塞队列广泛应用于任务调度、日志系统、消息中间件等场景。
基本上就这些。只要理解了互斥锁和条件变量的协作机制,阻塞队列的实现并不复杂,但非常实用。
以上就是c++++ 怎么实现一个阻塞队列_c++多线程通信与阻塞队列实现方法的详细内容,更多请关注其它相关文章!
相关文章:
将JSON对象数组转置为键值对列表的实用指南
Win11怎么设置开机NumLock亮 Win11修改注册表InitialKeyboardIndicators值
Win10如何开启蓝牙功能_Windows10找不到蓝牙开关解决方法
黑鲨3Pro怎样在相册开漫画风滤镜_iPhone黑鲨3Pro相册开漫画风滤镜【趣味滤镜】
文心一言怎样用插件调度API数据_文心一言用插件调度API数据【API调用】
age动漫网站入口 age动漫官网直接访问入口
c++如何使用Meson构建系统_c++比CMake更快的构建工具
葱吃多了会怎样 葱吃多了会伤胃吗
铁路12306卧铺选择攻略 铁路12306下铺座位预定技巧
解决Flask中Quill编辑器内容提交失败及TypeError的指南
Spyder启动失败:字体文件权限拒绝错误解决方案
QQ邮箱网页版入口登录 QQ邮箱在线邮箱官方通道
c++ dfs和bfs代码 c++深度广度优先搜索算法
Golang如何实现微服务鉴权与权限控制_Golang微服务鉴权与权限管理实践
构建轻量级网站内部消息系统:Formspree 集成指南
如何将HTML表格多行数据保存到Google Sheet
PDO预处理语句中冒号的正确处理:区分SQL函数格式与命名占位符
Golang并发任务中错误如何聚合_Golang goroutine error收集方式
Lar*el表单中优雅地处理“返回”按钮以规避验证:最佳实践指南
迅雷下载到U盘速度很慢怎么办_迅雷U盘下载慢优化方法
Go语言:非阻塞式判断标准输入(os.Stdin)是否有数据
Mac怎么使用表情符号_Mac Emoji快捷键面板
Windows10怎么开启存储感知 Windows10系统设置自动清理临时文件释放C盘空间【教程】
Golang如何通过reflect操作map_Golang reflect map操作与遍历技巧
绝地鸭卫平a核爆刀流玩法攻略
HTML5原生日期选择器与jQuery UI:实现日期选择器的联动与程序化控制
Lar*el Eloquent:高效统计带条件关联模型的数量
小米14应用无法联网原因分析_小米14网络权限修复
“音游” × “怪文书” 题材的节奏冒险游戏 《晕晕电波症候群》确定于2026年4月发售!
Composer的 "conflict" 字段有什么用_如何声明不兼容的包以避免依赖冲突
荒野行动PC版怎么注册_荒野行动PC版账号注册详细流程图文教程
拼多多视频播放卡顿如何处理 拼多多视频播放优化技巧
网站内容防复制粘贴的实现策略与局限性
Win10快速启动功能利弊分析 Win10开启或关闭快速启动教程【技巧】
ArrayList与LinkedList操作复杂度详解:遍历与修改
J*a里如何使用forEach遍历Map_Map遍历方法说明
在VS Code中配置和运行Dart程序的完整步骤
qq游戏手机版下载安装_qq游戏移动端入口
荣耀Play7TPro怎样在信息App置顶客服对话_iPhone荣耀Play7TPro信息App置顶客服对话【优先查看】
Vue.js 图片显示异常排查:理解应用挂载范围与DOM ID唯一性
J*aScript井字棋(Tic-Tac-Toe)核心交互逻辑实现教程
UC浏览器如何安装插件 UC浏览器添加扩展程序详细教程【进阶】
J*a中实现Go语言select通道多路复用机制
html怎么运行外部js文件中的函数_运html外js文件函数法【技巧】
漫蛙MANWA漫画主页官方入口 漫蛙漫画最新在线阅读地址
uc浏览器网页版入口 uc浏览器网页版最新网址
J*aScript中正确使用querySelectorAll与复杂CSS选择器
谷歌浏览器最新官方入口链接 谷歌浏览器网页版官网导航
PHP文件上传至S3:策略、考量与避免本地存储的挑战
TikTok搜索不到用户发布内容怎么办 TikTok用户内容搜索优化方法