Boost高性能并发无锁队列指南:boost::lockfree::queue
liuian 2025-04-24 03:25 15 浏览
1. 库的介绍
boost::lockfree::queue是Boost C++库中lockfree模块的一部分,它提供了一个线程安全的无锁队列实现。无锁队列允许多个线程在不使用互斥锁的情况下并发地访问共享数据结构,从而避免了传统锁带来的线程阻塞和上下文切换开销。
该组件位于Boost库的boost/lockfree/queue.hpp头文件中,要使用它需要先安装Boost库(1.53.0版本以上),并包含相应的头文件:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <thread>
#include <vector>
2. 主要功能与特点
2.1 主要功能
- 线程安全:多线程环境下无需额外同步机制
- 先进先出(FIFO)队列:保证数据按顺序处理
- 多生产者多消费者(MPMC)支持:适用于复杂并发场景
- 无阻塞操作:入队和出队操作不会阻塞线程
- 容量配置:支持固定大小和动态大小队列
2.2 特点
- 高性能:相比互斥锁实现,在高并发情况下性能显著提升
- 无死锁风险:不使用锁,因此不存在死锁问题
- 适合实时系统:操作延迟低且可预测
- 内存一致性:提供良好的内存序保证
- ABA问题的解决:内部实现解决了无锁编程中的ABA问题
3. 应用场景
boost::lockfree::queue特别适合以下场景:
- 高性能计算:需要线程间快速数据交换的场景
- 实时系统:对延迟敏感的应用程序
- 消息传递系统:作为线程间通信的媒介
- 生产者-消费者模式:一方生产数据,另一方消费数据
- 事件处理系统:处理高频率事件流
- 游戏引擎:需要低延迟线程通信的游戏场景
4. 详细功能模块与代码示例
4.1 基本用法
#include <boost/lockfree/queue.hpp>
#include <iostream>
int main()
{
// 创建一个容量为100的固定大小无锁队列
boost::lockfree::queue<int> queue(100);
// 入队操作
int value = 42;
bool success = queue.push(value);
if (success) {
std::cout << "成功将 " << value << " 入队\n";
} else {
std::cout << "入队失败,队列可能已满\n";
}
// 出队操作
int result;
if (queue.pop(result)) {
std::cout << "成功出队: " << result << "\n";
} else {
std::cout << "出队失败,队列可能为空\n";
}
return 0;
}
4.2 固定大小与动态大小队列
#include <boost/lockfree/queue.hpp>
#include <iostream>
int main()
{
// 固定大小队列 - 构造时指定容量
boost::lockfree::queue<int> fixed_queue(100);
// 动态大小队列 - 使用模板参数指定
boost::lockfree::queue<int, boost::lockfree::capacity<0>> dynamic_queue;
// 或使用fixed_sized标志禁用动态大小
boost::lockfree::queue<int, boost::lockfree::fixed_sized<false>> another_dynamic_queue;
// 检查队列是否为固定大小
std::cout << "固定队列是固定大小: " << fixed_queue.is_lock_free() << std::endl;
std::cout << "动态队列是固定大小: " << dynamic_queue.is_lock_free() << std::endl;
return 0;
}
值得注意的是,动态大小队列内部使用了节点分配器,可能导致在某些操作中发生内存分配,这可能影响实时性能。
4.3 多生产者多消费者模式
这是boost::lockfree::queue最常见的使用场景:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
boost::lockfree::queue<int> queue(1000);
std::atomic<bool> done(false);
std::atomic<int> produced_count(0);
std::atomic<int> consumed_count(0);
void producer(int id)
{
for (int i = 0; i < 1000; ++i) {
int value = id * 10000 + i;
while (!queue.push(value)) {
// 队列满时,让出CPU时间片
std::this_thread::yield();
}
produced_count.fetch_add(1);
}
}
void consumer()
{
int value;
while (!done || !queue.empty()) {
if (queue.pop(value)) {
consumed_count.fetch_add(1);
// 处理value,这里只是简单打印
if (consumed_count % 1000 == 0) {
std::cout << "已消费: " << consumed_count << " 项\n";
}
} else {
std::this_thread::yield();
}
}
}
int main()
{
// 创建生产者线程
std::vector<std::thread> producers;
for (int i = 0; i < 4; ++i) {
producers.push_back(std::thread(producer, i));
}
// 创建消费者线程
std::vector<std::thread> consumers;
for (int i = 0; i < 2; ++i) {
consumers.push_back(std::thread(consumer));
}
// 等待所有生产者完成
for (auto& t : producers) {
t.join();
}
// 通知消费者所有生产已完成
done = true;
// 等待所有消费者完成
for (auto& t : consumers) {
t.join();
}
std::cout << "生产项总数: " << produced_count << std::endl;
std::cout << "消费项总数: " << consumed_count << std::endl;
return 0;
}
4.4 批量操作
boost::lockfree::queue提供了批量入队和出队操作,可以提高性能:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <vector>
int main()
{
boost::lockfree::queue<int> queue(100);
// 准备批量入队的数据
std::vector<int> items_to_push = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 批量入队
size_t pushed = queue.push(items_to_push.begin(), items_to_push.end());
std::cout << "成功入队 " << pushed << " 个元素\n";
// 批量出队
std::vector<int> results(10);
size_t popped = queue.pop(results.begin(), results.end());
std::cout << "成功出队 " << popped << " 个元素: ";
for (size_t i = 0; i < popped; ++i) {
std::cout << results[i] << " ";
}
std::cout << std::endl;
return 0;
}
4.5 消费者遍历
可以使用consume_one和consume_all函数结合回调函数处理队列中的元素:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <functional>
int main()
{
boost::lockfree::queue<int> queue(100);
// 添加一些元素
for (int i = 0; i < 10; ++i) {
queue.push(i);
}
// 使用consume_one处理单个元素
bool consumed = queue.consume_one([](int value) {
std::cout << "consume_one处理元素: " << value << std::endl;
});
std::cout << "consume_one " << (consumed ? "成功" : "失败") << std::endl;
// 使用consume_all处理所有元素
size_t consumed_count = queue.consume_all([](int value) {
std::cout << "consume_all处理元素: " << value << std::endl;
});
std::cout << "consume_all处理了 " << consumed_count << " 个元素\n";
return 0;
}
4.6 队列容量与状态查询
boost::lockfree::queue提供了查询队列状态的方法:
#include <boost/lockfree/queue.hpp>
#include <iostream>
int main()
{
boost::lockfree::queue<int> queue(10);
// 填充队列
for (int i = 0; i < 5; ++i) {
queue.push(i);
}
// 检查队列是否为空
std::cout << "队列是否为空: " << (queue.empty() ? "是" : "否") << std::endl;
// 获取队列当前大小(近似值)
// 注意:在并发环境中这个值只是一个估计
std::cout << "队列大小估计: " << queue.read_available() << std::endl;
// 清空队列
queue.consume_all([](int){});
std::cout << "清空后队列是否为空: " << (queue.empty() ? "是" : "否") << std::endl;
return 0;
}
4.7 高级配置选项
boost::lockfree::queue提供了多种配置选项来满足不同需求:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <boost/pool/pool_alloc.hpp>
// 自定义分配器
typedef boost::fast_pool_allocator<int> pool_allocator;
int main()
{
// 使用自定义分配器的队列
boost::lockfree::queue<int, boost::lockfree::allocator<pool_allocator>> custom_alloc_queue(100);
// 配置固定大小
boost::lockfree::queue<int, boost::lockfree::fixed_sized<true>> fixed_queue(100);
// 自定义内存对齐
boost::lockfree::queue<int, boost::lockfree::alignment<16>> aligned_queue(100);
// 组合多个选项
boost::lockfree::queue<
int,
boost::lockfree::capacity<1000>, // 固定容量
boost::lockfree::fixed_sized<true>, // 固定大小
boost::lockfree::allocator<pool_allocator> // 自定义分配器
> advanced_queue;
// 测试队列功能
for (int i = 0; i < 10; ++i) {
custom_alloc_queue.push(i);
fixed_queue.push(i);
aligned_queue.push(i);
advanced_queue.push(i);
}
int value;
while (custom_alloc_queue.pop(value)) {
std::cout << "自定义分配器队列元素: " << value << std::endl;
}
return 0;
}
4.8 性能优化与最佳实践
在使用boost::lockfree::queue时,以下最佳实践可以帮助您获得最佳性能:
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <atomic>
// 性能测试示例
void performance_test()
{
// 使用合适的队列大小,避免频繁的内存分配
constexpr size_t QUEUE_SIZE = 10000;
boost::lockfree::queue<int, boost::lockfree::fixed_sized<true>> queue(QUEUE_SIZE);
std::atomic<bool> start{false};
std::atomic<int> ready_producers{0};
std::atomic<int> ready_consumers{0};
std::atomic<bool> done{false};
// 生产者
auto producer = [&](int id, int items) {
ready_producers++;
while (!start.load(std::memory_order_acquire)) {
std::this_thread::yield(); // 等待开始信号
}
for (int i = 0; i < items; ++i) {
int value = id * 1000000 + i;
// 使用批量入队来提高性能
if (i % 100 == 0 && i > 0) {
std::vector<int> batch;
for (int j = 0; j < 100; ++j) {
batch.push_back(value - 100 + j);
}
queue.push(batch.begin(), batch.end());
} else {
// 当队列满时进行指数退避
int retry = 0;
while (!queue.push(value)) {
if (++retry > 10) {
std::this_thread::sleep_for(std::chrono::microseconds(1 << std::min(retry, 10)));
} else {
std::this_thread::yield();
}
}
}
}
};
// 消费者
auto consumer = [&]() {
ready_consumers++;
while (!start.load(std::memory_order_acquire)) {
std::this_thread::yield(); // 等待开始信号
}
std::vector<int> batch(100);
int value;
while (!done || !queue.empty()) {
// 尝试批量出队
size_t popped = queue.pop(batch.begin(), batch.end());
if (popped > 0) {
// 处理批量数据
continue;
}
// 单个出队
if (queue.pop(value)) {
// 处理单个元素
} else {
// 智能退避,避免CPU空转
std::this_thread::yield();
}
}
};
// 创建线程
constexpr int NUM_PRODUCERS = 4;
constexpr int NUM_CONSUMERS = 4;
constexpr int ITEMS_PER_PRODUCER = 100000;
std::vector<std::thread> producers;
std::vector<std::thread> consumers;
for (int i = 0; i < NUM_PRODUCERS; ++i) {
producers.emplace_back(producer, i, ITEMS_PER_PRODUCER);
}
for (int i = 0; i < NUM_CONSUMERS; ++i) {
consumers.emplace_back(consumer);
}
// 等待所有线程就绪
while (ready_producers < NUM_PRODUCERS || ready_consumers < NUM_CONSUMERS) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// 开始计时
auto start_time = std::chrono::high_resolution_clock::now();
// 发出开始信号
start.store(true, std::memory_order_release);
// 等待生产者完成
for (auto& t : producers) {
t.join();
}
// 标记生产者已完成
done = true;
// 等待消费者完成
for (auto& t : consumers) {
t.join();
}
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
std::cout << "处理 " << NUM_PRODUCERS * ITEMS_PER_PRODUCER
<< " 项数据耗时: " << duration.count() << " 毫秒" << std::endl;
std::cout << "每秒处理约 "
<< (NUM_PRODUCERS * ITEMS_PER_PRODUCER * 1000.0 / duration.count())
<< " 项" << std::endl;
}
int main()
{
performance_test();
return 0;
}
4.9 与其他Boost组件结合使用
boost::lockfree::queue可以与其他Boost组件结合使用,实现更复杂的功能:
#include <boost/lockfree/queue.hpp>
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <thread>
#include <functional>
// 任务队列类示例
class TaskQueue {
private:
boost::lockfree::queue<std::function<void()>*> task_queue{1000};
boost::asio::io_context io_context;
std::unique_ptr<boost::asio::io_context::work> work;
std::vector<std::thread> worker_threads;
std::atomic<bool> running{false};
public:
TaskQueue(int num_threads = 4) : work(std::make_unique<boost::asio::io_context::work>(io_context)) {
running = true;
// 启动工作线程
for (int i = 0; i < num_threads; ++i) {
worker_threads.emplace_back([this]() {
while (running) {
// 尝试从队列中获取任务
std::function<void()>* task = nullptr;
if (task_queue.pop(task)) {
if (task) {
// 执行任务
(*task)();
delete task;
}
} else {
// 没有任务时处理IO事件
io_context.poll_one();
std::this_thread::yield();
}
}
});
}
}
~TaskQueue() {
stop();
}
// 提交任务
template<typename F>
bool submit(F&& task) {
auto* task_ptr = new std::function<void()>(std::forward<F>(task));
bool success = task_queue.push(task_ptr);
if (!success) {
delete task_ptr;
}
return success;
}
// 定时任务
template<typename F>
void schedule_after(int milliseconds, F&& task) {
auto timer = std::make_shared<boost::asio::steady_timer>(io_context);
timer->expires_after(std::chrono::milliseconds(milliseconds));
timer->async_wait([timer, task = std::forward<F>(task)](const boost::system::error_code& ec) {
if (!ec) {
task();
}
});
}
// 停止队列处理
void stop() {
if (running) {
running = false;
work.reset();
io_context.stop();
for (auto& thread : worker_threads) {
if (thread.joinable()) {
thread.join();
}
}
worker_threads.clear();
// 清空剩余任务
std::function<void()>* task = nullptr;
while (task_queue.pop(task)) {
delete task;
}
}
}
};
// 使用示例
int main() {
TaskQueue task_queue(4);
// 提交普通任务
for (int i = 0; i < 10; ++i) {
task_queue.submit([i]() {
std::cout << "执行任务 " << i << " 在线程 "
<< std::this_thread::get_id() << std::endl;
});
}
// 提交延迟任务
task_queue.schedule_after(1000, []() {
std::cout << "1秒后执行的定时任务" << std::endl;
});
// 等待任务完成
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
5. 注意事项与限制
使用boost::lockfree::queue时需要注意以下几点:
- 内存一致性:无锁队列依赖特定的内存序来保证正确性,不当使用可能导致难以发现的并发问题。
- 固定大小限制:固定大小队列可能会因队列满而拒绝新元素,必须有处理这种情况的策略。
- 动态内存分配:动态大小队列可能在运行时进行内存分配,这可能不适合对延迟敏感的应用程序。
- ABA问题:虽然boost::lockfree::queue内部处理了ABA问题,但了解这一问题有助于理解实现细节。
- 原子操作开销:无锁队列虽然避免了锁的开销,但原子操作本身也有一定代价,在低竞争环境下可能不如简单的锁实现快。
- 对齐要求:某些平台上的原子操作可能需要特定的内存对齐,boost::lockfree::queue会自动处理这些要求。
6. 总结
boost::lockfree::queue是一个强大的无锁队列实现,能够在多线程环境中提供高性能的数据交换。它无需使用互斥锁,因此避免了与锁相关的多种问题,特别适合对延迟敏感或高并发的应用场景。
相关推荐
- Docker 47 个常见故障的原因和解决方法
-
【作者】曹如熙,具有超过十年的互联网运维及五年以上团队管理经验,多年容器云的运维,尤其在Docker和kubernetes领域非常精通。Docker是一种相对使用较简单的容器,我们可以通过以下几种方式...
- 电脑30个快问快答,解决常见电脑问题
-
1.强行关机/停电对电脑有影响吗?答:可能损坏硬盘(机械硬盘风险高)、未保存数据丢失,偶尔一次影响小,但频繁操作会缩短硬件寿命。2.C盘满影响速度吗?答:会!系统运行需C盘空间缓存临时数据,空间不...
- 使用Tcpdump包抓取分析数据包的详细用法
-
TcpDump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。tcpdump就是一种...
- 电脑启动不了(BootDevice Not Found Hard Disk-3F0)解决方案
-
HP品牌机,开机启动不了,黑屏,开机取下主板电池恢复BIOS后,开机显示找不到启动盘。一、按F2键进入BIOS,出现硬盘内存检测界面的话,直接退出。就会出现这个界面,光标键向下,选择BIOSSetu...
- 电脑开机黑屏别慌!快码住!起底维修老师傅不能说的秘密
-
按下开机键却只收获黑屏大礼包?那些神秘的英文提示、刺耳的蜂鸣声,其实是电脑在给你发送求救信号!从按下电源到进入桌面的12秒里,你的电脑经历了史诗级的硬件自检与系统加载,今天我们就破译这段“摩斯电码”。...
- 电脑启动故障为何总要先看BIOS?新手必读的关键知识解析
-
最近在帮朋友们解答电脑无法正常开机的问题时,发现大家经常收到一句高频建议:“先检查BIOS”。对不少普通用户而言,BIOS依然是个神秘的存在。那么,BIOS到底是什么?电脑出现哪些故障会与它相关呢?本...
- Windows 11 KB5053598更新:安全补丁还是系统噩梦?
-
2025年3月11日,微软发布了Windows1124H2的强制性更新KB5053598,作为“周二补丁日”(PatchTuesday)的一部分。然而,这款本应提升系统安全性的更新却引发了广泛的...
- 飞牛OS入门安装遇到问题,如何解决?
-
之前小编尝试了用旧电脑装飞牛OS安装之前特意查了一些硬件要求飞牛OS目前支持主流的x86架构硬件主机需能连网线飞牛OS暂时不支持只有无线网卡的安装貌似很多小伙伴在一开始安装就卡住了那今天咱们汇总分...
- 几种常见的电脑开机黑屏显示白色英文字母解决方法
-
当电脑开机出现黑屏并显示白色英文字母时,通常表示系统启动过程中遇到了错误。以下是几种常见原因及对应的解决方法,按照排查顺序整理:一、检查外接设备与硬件连接可能原因:外接U盘、移动硬盘等未拔出,或内部硬...
- 电脑启动出现问题,为什么都要先检查BIOS?
-
【ZOL中关村在线原创技巧应用】最近在回答问题的时候,总会发现很多朋友都在问“电脑无法正常开机怎么办?”这样类似的问题,而许多DIY大佬的回复总会出现一条高频建议“先检查BIOS”。但对于许多普通用户...
- 教你怎么用JavaScript检测当前浏览器是无头浏览器
-
什么是无头浏览器(headlessbrowser)?无头浏览器是指可以在图形界面情况下运行的浏览器。我可以通过编程来控制无头浏览器自动执行各种任务,比如做测试,给网页截屏等。为什么叫“无头”浏览器?...
- 12个高效的Python爬虫框架,你用过几个?
-
实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...
- 运维的报表之路,用 node.js 轻松发送 grafana 报表
-
在运维过程中,无论是监控还是报表,都会有一些通过邮件发送图表的需求,由于开源的zabbix,grafana和kibana等并不完全具有“想发送哪儿就发送哪儿”的图片生成功能,在grafana...
- C#基于浏览器内核的高级爬虫(c#爬取网页内容)
-
基于C#.NET+PhantomJS+Sellenium的高级网络爬虫程序。可执行Javascript代码、触发各类事件、操纵页面Dom结构、甚至可以移除不喜欢的CSS样式。很多网站都用Ajax动态加...
- 如何优化一个秒杀项目?(秒杀实现思路)
-
问题1:使用jmeter性能压测,定位瓶颈代码步骤流程:线程组--->Http请求--->查看结果树--->聚合报告tips:host的文件--->优先调用映射,减少DNS的时...
- 一周热门
-
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
python使用fitz模块提取pdf中的图片
-
《人人译客》如何规划你的移动电商网站(2)
-
Jupyterhub安装教程 jupyter怎么安装包
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- table.render (33)
- uniapp textarea (33)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- react-admin (33)
- vscode切换git分支 (35)
- vscode美化代码 (33)
- python bytes转16进制 (35)