恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

folly 无锁单生产者单消费者队列 ProducerConsumerQueue 深度指南

  • 首页
  • 资讯中心
  • /
  • folly 无锁单生产者单消费者队列 ProducerConsumerQueue 深度指南

相关资讯

Ginkgo Cloud Lab 无细胞蛋白表达与 Strep-tag 纯化 A280 定量协议实战指南 2026/9/10 10:00:38
freeCodeCamp 每日编程挑战 364:用加权平均混合两桶 RGB 颜料(Between Two Buckets) 2026/9/10 10:00:38
RuView 隐私防护盾(WiFi Veil)超参数优化:从手工配置到鲁棒性验证的 Givens 混合与反馈量化最优解 2026/9/10 10:00:38

最新资讯

Sunshine:8步快速搭好你的游戏串流服务器
PyTorch+SB3构建可实盘的股票强化学习交易框架
Angular Query 快速上手:基于 Signals 的异步数据获取、缓存与服务端状态管理
Novu Providers 通道适配层全解析:从 2.0.2 到 2.6.6 的架构演进与关键变更
嵌入式硬件数据类设计优化与性能提升
VB.NET自定义仪表盘控件:GDI+绘图与工业HMI集成

今日推荐

AI搜索重构内容生态:企业从“流量争夺”转向“答案共建”
AI搜索的信任缺口:企业内容如何在答案时代自证可信
Spring Boot+Vue+Node.js售后服务系统开发实战

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

folly 无锁单生产者单消费者队列 ProducerConsumerQueue 深度指南

发布时间:2026/9/10 10:00:38
folly 无锁单生产者单消费者队列 ProducerConsumerQueue 深度指南 folly 无锁单生产者单消费者队列 ProducerConsumerQueue 深度指南【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/follyfolly::ProducerConsumerQueue是 Meta 开源的 C 基础库 folly 中一个面向单生产者、单消费者SPSC场景的高性能无锁有界队列。它的所有操作都是 wait-free无等待的同步开销极低是构建日志管道、事件流水线、线程间任务传递等一对一线程通信场景的理想选择。读完本文你将掌握它的核心 API、wait-free 实现原理、容量语义、线程使用约束以及如何结合 folly 源码中的测试与基准用例把它正确应用到自己的项目中。队列定位与适用场景在 folly/docs/Overview.md 中该队列被概括为 Lock free single-reader, single-writer queue无锁单读单写队列。它与同目录下的MPMCQueue支持多生产者、多消费者、可选阻塞的高性能有界并发队列形成互补ProducerConsumerQueue只允许一个生产者线程写、一个消费者线程读因此可以省去锁与复杂的并发协调获得极低的同步开销MPMCQueue面向更通用的多生产者多消费者场景能力更强但开销也更高。在 folly 内部folly::coro::BoundedQueue在SingleProducer SingleConsumer即 SPSC模式下就直接复用了ProducerConsumerQueue作为底层存储见 folly/coro/BoundedQueue.h并在构造时额外多分配一个槽位以补偿可用容量为 size-1的语义folly::concurrency::UnboundedQueue的文档注释中也将ProducerConsumerQueue作为 SPSC 场景的对照实现见 folly/concurrency/UnboundedQueue.h。这些内部复用点说明当业务模型天然是一个线程产生、一个线程消费时该队列就是 folly 官方推荐的默认选择。核心 API 一览队列在构造时必须指定固定的最大槽位数会一次性分配sizeof(T) * size的内存随后只提供少量简单操作。以下接口全部声明于 folly/ProducerConsumerQueue.h方法作用返回/行为read(T record)将队首元素移动或拷贝到给定变量中队列为空时返回falsewrite(Args... recordArgs)在队尾原位构造一个新元素支持任意构造参数直接转发队列已满时返回falsefrontPtr()返回队首元素的指针供原地使用队列为空时返回nullptrpopFront()弹出队首元素队列必须非空空时触发断言isEmpty()判断队列是否为空boolisFull()判断队列是否已满boolsizeGuess()估算队列中的元素个数size_t估算值capacity()队列可容纳的最大元素数恒等于size - 1从源码可见write是一个可变参数模板folly/ProducerConsumerQueue.h通过 placement new 在预分配内存上以T(std::forwardArgs(recordArgs)...)原位构造元素因此可以像queue.write(1, 2)这样直接在队列中构造多参数类型避免先构造再拷贝的额外开销。容量语义为什么 size 要加 1理解该队列最关键的一点是构造时传入的size是底层缓冲区的槽位总数而实际可同时容纳的元素数是size - 1。capacity()方法的实现直接返回size_ - 1见 folly/ProducerConsumerQueue.h构造函数的注释也明确写道从空队列开始插入size - 1个元素后isFull()就会返回true。这一点有两个直接后果size必须 2。构造函数以assert(size 2)强制这一前提folly/ProducerConsumerQueue.h否则容量会退化为 0 或负数分配内存时要为语义差预留空间。例如 folly coro 的 BoundedQueue 在 SPSC 模式下就执行capacity 1的分配folly/coro/BoundedQueue.h正是为了抵消ProducerConsumerQueue的size-1语义。单元测试 folly/test/ProducerConsumerQueueTest.cpp 中的EmptyFull与Capacity两个用例精确验证了这套语义folly::ProducerConsumerQueueint queue(3); EXPECT_TRUE(queue.isEmpty()); EXPECT_TRUE(queue.write(1)); EXPECT_TRUE(queue.write(2)); EXPECT_TRUE(queue.isFull()); // 关键写入 2 次即满而非 3 次 EXPECT_FALSE(queue.write(3)); EXPECT_EQ(queue.sizeGuess(), 2); EXPECT_EQ(queue.capacity(), 2); // 容量 缓冲区槽位数 - 1wait-free 实现原理与无锁lock-free相比无等待wait-free是更强的进度保证每个线程的操作都能在有限步数内完成不会被其他线程饿死。该队列之所以能做到 wait-free核心在于两点设计均可在 folly/ProducerConsumerQueue.h 中看到1. 双原子索引 环形缓冲队列仅依赖两个std::atomicunsigned int索引readIndex_与writeIndex_在一个预分配的环形缓冲records_上推进writerelaxed读writeIndex_计算下一个槽位若与acquire读到的readIndex_相等则判定已满否则原位构造元素并以release语义发布新索引folly/ProducerConsumerQueue.hreadrelaxed读readIndex_若与acquire读到的writeIndex_相等则判定为空否则移出元素、显式析构并以release语义推进读索引folly/ProducerConsumerQueue.h。借助memory_order_acquire/memory_order_release配对生产者写入的数据对消费者可见而两个线程各自只写自己的索引天然规避了竞争因此每次操作都只有两条原子指令全程无锁、无等待、无系统调用。2. 缓存行对齐消除伪共享两个索引字段分别用alignas(hardware_destructive_interference_size)对齐该常量来自folly/concurrency/CacheLocality.h通常等于 CPU 缓存行大小 64 字节并在结构体首尾以pad0_、pad1_填充。这样生产者的writeIndex_与消费者的readIndex_不会落在同一条缓存行上避免了双方频繁刷新彼此缓存行的伪共享开销——这是该队列极低同步开销的关键工程细节之一。3. 手动生命周期管理缓冲区通过std::malloc一次性分配失败时抛出std::bad_alloc见 folly/ProducerConsumerQueue.h。元素以 placement new 就地构造、以显式~T()析构析构函数会遍历readIndex_到writeIndex_之间的所有遗留元素并逐一销毁对平凡析构类型直接跳过见 folly/ProducerConsumerQueue.h。测试 folly/test/ProducerConsumerQueueTest.cpp 中的Destructor用例专门验证了队列退出时孤儿元素包括写索引回绕后的场景都能被正确销毁不会泄漏资源。线程使用规则与注意事项文档与源码共同强调了以下约束违反任意一条都属于未定义行为读操作read、frontPtr、popFront只能由消费者线程调用写操作write只能由生产者线程调用isEmpty、isFull、sizeGuess两个线程都可以调用但返回值语义有讲究sizeGuess()只能从生产者或消费者线程调用。源码注释明确说明folly/ProducerConsumerQueue.h消费者调用时真实值可能偏大生产者正在并发入队生产者调用时真实值可能偏小消费者正在并发出队而从其他线程调用结果是未定义的——因为它只是两个索引的差值无法保证与任何一致快照对应文档同时指出多数场景下read/write/frontPtr的返回结果已经足够isFull/isEmpty/sizeGuess更多用于调试或容量规划。关于满/空失败的处理write在队列满时返回falseread在队列空时返回false因此在很多实际场景中选择队列容量时应让队列填满或长时间为空成为小概率事件从而保证两个线程绝大多数时间都能一次成功。若满/空成为常态则消费者/生产者会陷入忙等自旋白白消耗 CPU见 folly/docs/ProducerConsumerQueue.md。使用示例以下两个示例来自 folly/docs/ProducerConsumerQueue.md可直接编译运行。示例使用folly::fbstring作为元素类型sink(str)与source()代表你的业务处理与数据来源。示例一read/write经典自旋模式folly::ProducerConsumerQueuefolly::fbstring queue{size}; std::thread reader([queue] { for (;;) { folly::fbstring str; while (!queue.read(str)) { // 自旋等待直到拿到一个值 continue; } sink(str); } }); // 生产者线程 for (;;) { folly::fbstring str source(); while (!queue.write(str)) { // 自旋等待直到队列腾出空间 continue; } }示例二frontPtrpopFront原地处理避免移动/拷贝如果消费方希望直接在队首元素上做处理例如处理大对象、避免一次额外的移动或拷贝可以改用指针式 APIstd::thread reader([queue] { for (;;) { folly::fbstring* pval; do { pval queue.frontPtr(); } while (!pval); // 自旋等待直到拿到值 sink(*pval); // 原地使用队首元素 queue.popFront(); // 处理完毕后弹出 } });需要注意popFront要求队列非空源码中带有assert见 folly/ProducerConsumerQueue.h因此必须在frontPtr()返回非空指针之后才能调用不可单独贸然调用。从测试与基准看正确性与性能特征仓库为队列提供了专门的测试与基准可作为验证与压测的参考起点正确性测试folly/test/ProducerConsumerQueueTest.cpp覆盖std::string、int、unsigned long long等类型的读写一致性、frontPtrpopFront消费路径、析构时遗留元素的销毁、空/满判定与容量语义基准测试folly/test/ProducerConsumerQueueBenchmark.cpp提供三个入口——BM_ProducerConsumer吞吐、BM_ProducerConsumerAffinity绑定 CPU 0/1 后的吞吐、BM_ProducerConsumerLatency生产者每秒注入一次消费端统计端到端延迟直方图。其中延迟测试以对数桶log-scale bucketing统计延迟分布输出 TSV 格式直方图可用于评估队列引入的延迟上界。该文件末尾保留了作者在一台 24 核 KVM 虚拟化 Intel 主机上的历史压测记录吞吐测试单次操作约 5.82ns约 1.7 亿次/秒绑定 CPU 亲和后约 7.36ns延迟测试中绝大多数样本落在 6~13 个对数桶区间。注意这是特定硬件与编译环境下的历史快照仅供参考不代表任何承诺的性能指标——如需在目标平台上复现可参照 folly/test/BUCK 中producer_consumer_queue_benchmark目标的构建方式自行编译运行。与其他 folly 队列的选型对照队列生产者/消费者阻塞适用场景ProducerConsumerQueue单/单SPSC否wait-free一对一线程管道、事件流、极低延迟路径MPMCQueue多/多MPMC可选阻塞通用任务分发、多线程工作池folly::coro::BoundedQueue可配置SPSC 时底层即 PCQ协程异步等待协程场景下的有界队列folly::concurrency::UnboundedQueue可配置无界无法预先确定容量上限的场景MPMCQueue的更多说明可参见 folly/docs/Overview.md。选型建议业务模型严格是一写一读、且追求极致吞吐与确定性延迟时选ProducerConsumerQueue一旦出现多个生产者或多个消费者就必须切换到 MPMC 系队列否则会违反本文所述的线程约束。小结folly::ProducerConsumerQueue用两个缓存行对齐的原子索引和一个预分配的环形缓冲区在单生产者单消费者这一受限但高频的场景下实现了真正的 wait-free 通信每次操作仅需两次原子访问无锁、无等待、无伪共享。使用时的三条铁律是size至少为 2 且真实容量是size - 1读/写 API 必须严格分属消费/生产线程sizeGuess()只允许在两个参与者线程内调用。掌握这些语义后你可以放心地把它嵌入日志管道、事件分发、流水线等一对一线程通信链路中获得可预期的低延迟与高吞吐。【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号