主页 > 互联网  > 

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

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

Linux 基于共享内存的循环队列实现 Linux 基于共享内存的循环队列实现一、共享内存与循环队列基础1.1 共享内存特性1.2 循环队列优势 二、系统关键技术分析2.1 共享内存操作APIshmget() 创建共享内存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.hdemo.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 使用流程 创建共享内存:shmget()映射到进程空间:shmat()手动初始化队列:init()正常队列操作分离映射:shmdt()(可选)删除共享内存: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 同步策略建议 互斥信号量:保护队列操作原子性空/满信号量:实现生产者-消费者模型超时机制:避免死锁错误恢复:处理进程异常退出
六、扩展应用场景 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); }
标签:

Linux基于共享内存的循环队列实现由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Linux基于共享内存的循环队列实现