共享内存是Linux系统最高效的进程间通信(IPC)方式,其特点包括:
与其他IPC方式对比:
通信方式 | 传输速度 | 数据持久性 | 使用复杂度 |
---|---|---|---|
共享内存 | 最快 | 系统重启前有效 | 中 |
管道 | 慢 | 进程结束失效 | 低 |
消息队列 | 中等 | 系统重启前有效 | 高 |
循环队列(Circular Queue)相比普通队列:
int shmid = shmget(key_t key, size_t size, int shmflg);
void* shmat(int shmid, const void* shmaddr, int shmflg);
template<class TT, int MaxLength>
class squeue {
// 禁止拷贝构造和赋值
squeue(const squeue &) = delete;
squeue &operator=(const squeue &) = delete;
TT m_data[MaxLength]; // 固定大小数组
// 队列指针和状态管理
};
设计特点:
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;
}
}
特殊处理原因:共享内存对象不会自动调用构造函数
bool push(const TT &ee) {
if(full()) return false;
m_tail = (m_tail+1)%MaxLength; // 先移动尾指针
m_data[m_tail] = ee; // 后写入数据
m_length++;
return true;
}
bool pop() {
if(empty()) return false;
m_head = (m_head+1)%MaxLength; // 移动头指针
m_length--;
return true;
}
// 创建信号量集
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); // 释放队列访问权
#ifndef __PUBLIC_HH
#define __PUBLIC_HH
#include
#include
#include
#include
#include
#include
#include
#include
#include
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
// 演示基于共享内存的循环队列
#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);
}