Linux 基于共享内存的循环队列实现

Linux 基于共享内存的循环队列实现

  • Linux 基于共享内存的循环队列实现
    • 一、共享内存与循环队列基础
      • 1.1 共享内存特性
      • 1.2 循环队列优势
    • 二、系统关键技术分析
      • 2.1 共享内存操作API
        • shmget() 创建共享内存
        • shmat() 映射共享内存
      • 2.2 模板类设计要点
    • 三、循环队列核心方法实现
      • 3.1 初始化方法
      • 3.2 入队操作
      • 3.3 出队操作
    • 四、共享内存实践要点
      • 4.1 使用流程
      • 4.2 关键注意事项
    • 五、进程同步问题解决方案
      • 5.1 信号量同步示例
      • 5.2 同步策略建议
    • 六、扩展应用场景
      • 6.1 高性能日志系统
      • 6.2 实时数据采集
      • 6.3 分布式计算中间件
    • 七、完整代码示例与测试结果
      • 7.1 完整代码示例
        • _public.h
        • demo.cpp

Linux 基于共享内存的循环队列实现

一、共享内存与循环队列基础

1.1 共享内存特性

共享内存是Linux系统最高效的进程间通信(IPC)方式,其特点包括:

  • 直接映射到进程地址空间
  • 数据无需在进程间复制
  • 访问速度接近内存访问
  • 需要手动处理同步问题

与其他IPC方式对比:

通信方式传输速度数据持久性使用复杂度
共享内存最快系统重启前有效
管道进程结束失效
消息队列中等系统重启前有效

1.2 循环队列优势

循环队列(Circular Queue)相比普通队列:

  • 有效利用预分配内存空间
  • 时间复杂度均为O(1)
  • 避免假溢出问题
  • 固定大小的特性适合共享内存场景

二、系统关键技术分析

2.1 共享内存操作API

shmget() 创建共享内存
int shmid = shmget(key_t key, size_t size, int shmflg);
  • key:0x5005为自定义标识
  • size:使用sizeof计算模板类大小
  • shmflg:0640权限+IPC_CREAT创建标志
shmat() 映射共享内存
void* shmat(int shmid, const void* shmaddr, int shmflg);
  • shmaddr设为0由系统选择映射地址
  • 返回类型强转为队列指针

2.2 模板类设计要点

template<class TT, int MaxLength>
class squeue {// 禁止拷贝构造和赋值squeue(const squeue &) = delete;squeue &operator=(const squeue &) = delete;TT m_data[MaxLength]; // 固定大小数组// 队列指针和状态管理
};

设计特点:

  • 模板化支持任意数据类型
  • 禁止拷贝防止浅复制问题
  • 内置初始化方法解决共享内存构造问题
  • 环形索引计算:(pos+1)%MaxLength

三、循环队列核心方法实现

3.1 初始化方法

void init() {if(!m_inited) {m_head = 0;m_tail = MaxLength-1; // 初始指向末尾m_length = 0;memset(m_data, 0, sizeof(m_data));m_inited = true;}
}

特殊处理原因:共享内存对象不会自动调用构造函数

3.2 入队操作

bool push(const TT &ee) {if(full()) return false;m_tail = (m_tail+1)%MaxLength; // 先移动尾指针m_data[m_tail] = ee;          // 后写入数据m_length++;return true;
}

3.3 出队操作

bool pop() {if(empty()) return false;m_head = (m_head+1)%MaxLength; // 移动头指针m_length--;return true;
}

四、共享内存实践要点

4.1 使用流程

  1. 创建共享内存:shmget()
  2. 映射到进程空间:shmat()
  3. 手动初始化队列:init()
  4. 正常队列操作
  5. 分离映射:shmdt()
  6. (可选)删除共享内存:shmctl()

4.2 关键注意事项

  • 数据持久性:共享内存会一直存在直到系统重启或主动删除
  • 多进程同步:必须使用信号量等同步机制
  • 内存对齐:确保数据结构在共享内存中正确对齐
  • 数据类型限制:建议使用POD(Plain Old Data)类型

五、进程同步问题解决方案

5.1 信号量同步示例

// 创建信号量集
int semid = semget(0x5005, 2, 0640|IPC_CREAT);// P操作函数
void P(int semid, int num) {struct sembuf sb = {num, -1, SEM_UNDO};semop(semid, &sb, 1);
}// V操作函数
void V(int semid, int num) {struct sembuf sb = {num, 1, SEM_UNDO};semop(semid, &sb, 1);
}// 使用示例
P(semid, 0); // 申请队列访问权
QQ->push(ee);
V(semid, 0); // 释放队列访问权

5.2 同步策略建议

  1. 互斥信号量:保护队列操作原子性
  2. 空/满信号量:实现生产者-消费者模型
  3. 超时机制:避免死锁
  4. 错误恢复:处理进程异常退出

六、扩展应用场景

6.1 高性能日志系统

  • 多生产者单消费者模式
  • 批量写入磁盘设计
  • 日志分级存储

6.2 实时数据采集

  • 传感器数据缓存
  • 多采集节点汇聚
  • 数据预处理流水线

6.3 分布式计算中间件

  • 任务分配队列
  • 结果收集缓冲区
  • 负载均衡控制器

七、完整代码示例与测试结果

7.1 完整代码示例

_public.h
#ifndef __PUBLIC_HH
#define __PUBLIC_HH#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>using namespace std;// 循环队列
template<class TT, int MaxLength>
class squeue
{
private:bool    m_inited;        // 队列初始化标志TT     m_data[MaxLength];    // 使用数组存储循环队列中的元素int    m_head;int    m_tail;int    m_length;squeue(const squeue &) = delete;        // 禁止拷贝构造函数squeue &operator=(const squeue &) = delete;    // 禁止赋值函数public:squeue() { init(); }    // 构造函数// 循环队列的初始化操作// 注意:如果用于共享内存的队列 不会调用构造函数 则必须调用此函数初始化 ???void init(){cout << "init\n";if(m_inited!=true){m_head=0;m_tail=MaxLength-1;m_length=0;memset(m_data, 0, sizeof(m_data));m_inited=true;}}// 元素入队bool push(const TT &ee){if(full() == true){cout << "循环队列已满,入队失败\n"; return false;}// 先移动队伍尾指针 再拷贝数据m_tail=(m_tail+1)%MaxLength;m_data[m_tail]=ee;m_length++;return true;}// 求循环队列的长度int size(){return m_length;}// 判断循环队列是否为空bool empty(){if(m_length == 0) return true;return false;}// 判断循环队列是否已满bool full(){if(m_length == MaxLength) return true;return false;}// 查看队头元素值,元素不出队TT& front(){return m_data[m_head];}// 元素出队bool pop(){if(empty() == true) return false;m_head=(m_head+1)%MaxLength;m_length--;return true;}// 显示村换队列的全部元素void printqueue(){for(int ii=0; ii<size(); ii++){cout << "m_data ii=" << ii << " [" << (m_head+ii)%MaxLength << "], value=" \<< m_data[(m_head+ii)%MaxLength] << endl;}}
};#endif
demo.cpp
// 演示基于共享内存的循环队列
#include "_public.h"int main()
{using ElemType=int;// 初始化共享内存int shmid=shmget(0x5005, sizeof(squeue<ElemType, 5>), 0640|IPC_CREAT);if(shmid == -1) {cout << "shmget(0x5005) failed\n";return -1;}// 将共享内存连接到当前进程的地址空间squeue<ElemType, 5>* QQ = (squeue<ElemType, 5>*)shmat(shmid, 0, 0);if(QQ == (void*)-1) {cout << "shmat() failed\n";return -1;}// 初始化循环队列 因为不会调用squeue的构造函数QQ->init();// 创建一个数据元素ElemType ee;cout << "元素(1 2 3)入队\n";ee=1; QQ->push(ee);ee=2; QQ->push(ee);ee=3; QQ->push(ee);cout << "队列长度为" << QQ->size() << endl;QQ->printqueue();ee=QQ->front(); QQ->pop(); cout << "出队伍元素值为" << ee << endl;ee=QQ->front(); QQ->pop(); cout << "出队伍元素值为" << ee << endl;cout << "队列长度为" << QQ->size() << endl;QQ->printqueue();cout << "元素(11 12 13 14 15)入队\n";ee=11; QQ->push(ee);ee=12; QQ->push(ee);ee=13; QQ->push(ee);ee=14; QQ->push(ee);ee=15; QQ->push(ee);cout << "队列长度为" << QQ->size() << endl;QQ->printqueue();// 将共享内存从进程中分离shmdt(QQ);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/69921.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第十九节】

ISO 14229-1:2023 UDS诊断服务测试用例全解析&#xff08;ClearDiagnosticInformation_0x84服务&#xff09; 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月14日 关键词&#xff1a;UDS协议、0x84服务、清除诊断信息、ISO 14229-1:2023、ECU测试 一、服…

盛铂科技 SMF106 低相位噪声贴片式频率综合器模块

在现代通信和电子设备领域&#xff0c;频率综合器作为关键组件&#xff0c;其性能优劣直接影响系统的整体表现。盛铂科技的 SMF106 低相位噪声贴片式频率综合器&#xff0c;以其卓越的性能和独特设计&#xff0c;成为众多高性能系统的选择。 一、频率覆盖范围广&#xff0c;步进…

Java语言在微服务架构中的应用研究

Java语言在微服务架构中的应用研究 微服务架构是现代软件系统中一种重要的设计模式&#xff0c;它通过将单一的应用程序拆解成多个小型、独立的服务来增强系统的可扩展性、灵活性和可维护性。Java作为一种成熟的编程语言&#xff0c;在微服务架构的实现中发挥了重要作用。本文…

深度解析前端性能优化:策略与实践

在当今数字化时代,前端性能对于用户体验和业务成功至关重要。缓慢加载的页面会导致用户流失,而高效的前端性能则能提升用户满意度、转化率和品牌形象。本文将深入探讨前端性能优化的关键策略与实践,帮助开发者打造快速响应的优质 Web 应用。 一、资源加载优化 1. 压缩与合…

Mybatis-扩展功能

逻辑删除乐观锁 MyBatisPlus从入门到精通-3&#xff08;含mp代码生成器&#xff09; Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解&#xff0c;很不灵活 希望用枚举类来代替这个Integer 这样的话我…

请解释设备像素、CSS 像素、设备独立像素、DPR、PPI 之间的区别?

设备像素&#xff08;Device Pixels&#xff09; 定义&#xff1a;设备像素&#xff0c;也称为物理像素&#xff0c;是屏幕上能够显示的最小物理单位。每个设备像素代表屏幕上的一个点&#xff0c;用于显示颜色。 代码示例&#xff1a; console.log(window.screen.width); /…

【golang】channel带缓存和不带缓存的区别,应用场景解读

在Go语言中&#xff0c;channel&#xff08;通道&#xff09;分为带缓存的通道&#xff08;Buffered Channel&#xff09;和不带缓存的通道&#xff08;Unbuffered Channel&#xff09;&#xff0c;它们的核心区别在于数据传递的同步机制和性能特性。以下是详细对比&#xff1a…

《Foundation 起步》

《Foundation 起步》 引言 在当今快速发展的科技时代,了解并掌握最新的技术是至关重要的。本文旨在为初学者提供一个全面的《Foundation》起步指南,帮助大家快速入门并掌握这一强大的技术。 一、什么是Foundation? Foundation 是一个流行的前端框架,由 ZURB 公司开发。…

Java Lambda 表达式的实践与思考

一、引言 自Java 8引入Lambda表达式以来&#xff0c;Java语言在函数式编程方面迈出了重要一步。Lambda不仅让代码变得更简洁&#xff0c;还极大地提升了对集合、流操作等场景下的处理能力。作为一名资深Java后端程序员&#xff0c;多年的开发实践让我深刻体会到Lambda在提升代…

记忆力训练day19

万能字母组合编码法 所有的文字和字母的背后都有画面 练的不是记单词&#xff0c;练的是注意力给到单词&#xff0c;出什么画面&#xff0c;然后画面与画面之间进行连接 拆的过程就是找熟词的过程 要关注自己的回忆路径是什么&#xff1f;也就是你是怎么回忆起来的&#xff0c…

【第13章:自监督学习与少样本学习—13.4 自监督学习与少样本学习的未来研究方向与挑战】

凌晨三点的实验室里,博士生小张盯着屏幕上的训练曲线——他设计的跨模态少样本学习模型在医疗影像诊断任务上突然出现了诡异的性能断崖。前一秒还在92%的准确率高位运行,下一秒就暴跌到47%。这个看似灾难性的现象,却意外揭开了自监督学习与少样本学习技术深藏的核心挑战… 一…

unity学习43:子状态机 sub-state machine

目录 1sub-state machine子状态机 1.1 创建 sub-state machine 1.2 sub-state machine 内容 1.3 子状态机的应用 2 子状态机不同于blend tree的嵌套 3 应用例子&#xff1a;若角色拿不同武器的动画设计&#xff0c;可以使用2种方法 3.1 在1个图层layer里&#xff0c;使用…

CANopen协议简介及电机控制

CANopen 是基于CAN总线的一种高层协议&#xff0c;广泛应用于工业自动化、嵌入式系统以及电机控制等领域。它的优点包括高效的数据传输能力、灵活的设备管理和强大的通信功能。 ​ 在控制多个电机并实时获取电机速度时&#xff0c;CANopen通过两种数据传输方式来实现&#xff…

20250213 隨筆 雪花算法

雪花算法&#xff08;Snowflake Algorithm&#xff09; 雪花算法&#xff08;Snowflake&#xff09; 是 Twitter 在 2010 年開發的一種 分布式唯一 ID 生成算法&#xff0c;它可以在 高併發場景下快速生成全局唯一的 64-bit 長整型 ID&#xff0c;且不依賴資料庫&#xff0c;具…

Golang并发编程最佳实践:协程与通道

Golang并发编程最佳实践&#xff1a;协程与通道 本文旨在介绍Golang并发编程的最佳实践&#xff0c;重点讨论协程和通道的使用方法&#xff0c;以及相关的实际案例和代码示例。 一、Golang并发编程简介 又称Go语言&#xff09;是一种由Google开发的编程语言&#xff0c;旨在提供…

Python VsCode DeepSeek接入

Python VsCode DeepSeek接入 创建API key 首先进入DeepSeek官网&#xff0c;https://www.deepseek.com/ 点击左侧“API Keys”&#xff0c;创建API key&#xff0c;输出名称为“AI” 点击“创建"&#xff0c;将API key保存&#xff0c;复制在其它地方。 在VsCode中下载…

【C++】基础入门(详解)

&#x1f31f; Hello&#xff0c;我是egoist2023&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; 目录 输入&输出 缺省参数(默认参数) 函数重载 引用 概念及定义 特性及使用 const引用 与指针的关系 内联inline和nullptr in…

【Elasticsearch】runtime_mappings搜索请求中定义运行时字段

在 Elasticsearch 中&#xff0c;在搜索请求中定义运行时字段&#xff08;Runtime Fields&#xff09;是一种强大的功能&#xff0c;允许用户在查询时动态添加和计算字段&#xff0c;而无需预先在索引映射中定义这些字段。这种方式提供了极大的灵活性&#xff0c;尤其是在处理动…

数学建模基础训练-1:概念解析

文章目录 数学建模基础训练-1&#xff1a;概念解析问题一&#xff1a;如何找到“概念”&#xff1f;问题二&#xff1a;如何全面理解概念的基础含义&#xff1f;问题三&#xff1a;如何深刻理解概念并作出创新点发掘&#xff1f;实际举例问题一 :研究并给出寒假开学某大学返校交…

【Linux基础】Linux下常用的系统命令

文章目录 一、前言二、系统监控和进程管理指令2.1 ps命令2.2 top命令2.3 kill命令2.4 shutdown命令 三、文件和目录管理指令3.1 cd命令3.2 ls命令3.3 mkdir命令3.4 cat 命令3.5 cp命令3.6 mv命令3.7 rm命令3.8 chmod命令3.9 ln命令3.10 pwd命令 四、文件查找和文本处理指令4.1 …