共享内存封装设计
一、共享内存由两个部分组成共享内存头部+共享内存数据区
共享内存头部定义
typedef struct shmhead_st
{
int shmid; // 共享内存ID
unsigned int blksize; // 块大小
unsigned int blocks; // 总块数
unsigned int rd_index; // 读索引
unsigned int wr_index; // 写索引
//必须放在共享内存内部才行
sem_t sem_mutex; // 用来互斥用的信号量
sem_t sem_full; // 用来控制共享内存是否满的信号量
sem_t sem_empty; // 用来控制共享内存是否空的信号量
}shmhead_t;
共享内存类定义
class ShmFIFO
{
public:
ShmFIFO(int key, int blksize, int blocks);
ShmFIFO();
virtual ~ShmFIFO();
//创建和销毁
bool ShmInit(int key, int blksize, int blocks);
void destroy(void);
static void ShmDestroy(int key); //静态删除共享内存方法
// 打开和关闭
bool ShmOpen(int key, int blksize, int blocks);
void ShmClose(void);
//读取和存储
void ShmWrite(const void *buf);
void ShmRead(void *buf);
protected:
//进程控制信息块
bool m_open;
void *m_shmhead; // 共享内存头部指针
char *m_payload; // 有效负载的起始地址
};
共享内存类实现
ShmFIFO::ShmFIFO(int key, int blksize, int blocks)
{
this->ShmOpen(key, blksize, blocks);
}
ShmFIFO::ShmFIFO()
{
m_shmhead = NULL;
m_payload = NULL;
m_open = false;
}
ShmFIFO::~ShmFIFO()
{
this->ShmClose();
}
//返回头地址
bool ShmFIFO::ShmInit(int key, int blksize, int blocks)
{
int shmid = 0;
//1. 查看是否已经存在共享内存,如果有则删除旧的
shmid = shmget((key_t)key, 0, 0);
if (shmid != -1)
{
shmctl(shmid, IPC_RMID, NULL); // 删除已经存在的共享内存
}
//2. 创建共享内存
shmid = shmget((key_t)key, sizeof(shmhead_t) + blksize*blocks, 0666 | IPC_CREAT | IPC_EXCL);
if(shmid == -1)
{
perror("shmget");
exit(-1);
}
printf("Create shmid=%d size=%ld \n", shmid, sizeof(shmhead_t) + blksize*blocks);
//3.连接共享内存
m_shmhead = shmat(shmid, (void*)0, 0); //连接共享内存
if(m_shmhead == (void*)-1)
{
perror("shmat");
exit(-1);
}
memset(m_shmhead, 0, sizeof(shmhead_t) + blksize*blocks); //初始化
//4. 初始化共享内存信息
shmhead_t * pHead = (shmhead_t *)(m_shmhead);
pHead->shmid = shmid; //共享内存shmid
pHead->blksize = blksize; //共享信息写入
pHead->blocks = blocks; //写入每块大小
pHead->rd_index = 0; //一开始位置都是第一块
pHead->wr_index = 0; //
sem_init(&pHead->sem_mutex, 1, 1); // 第一个1表示可以跨进程共享,第二个1表示初始值
sem_init(&pHead->sem_empty, 1, 0); // 第一个1表示可以跨进程共享,第二个0表示初始值
sem_init(&pHead->sem_full, 1, blocks);// 第一个1表示可以跨进程共享,第二个blocks表示初始值
//5. 填充控制共享内存的信息
m_payload = (char *)(pHead + 1); //实际负载起始位置
m_open = true;
return true;
}
void ShmFIFO::destroy()
{
shmhead_t *pHead = (shmhead_t *)m_shmhead;
int shmid = pHead->shmid;
//删除信号量
sem_destroy (&pHead->sem_full);
sem_destroy (&pHead->sem_empty);
sem_destroy (&pHead->sem_mutex);
shmdt(m_shmhead); //共享内存脱离
//销毁共享内存
if(shmctl(shmid, IPC_RMID, 0) == -1) //删除共享内存
{
printf("Delete shmid=%d \n", shmid);
perror("shmctl");
exit(-1);
}
m_shmhead = NULL;
m_payload = NULL;
m_open = false;
}
void ShmFIFO::ShmDestroy(int key)
{
int shmid = 0;
//1. 查看是否已经存在共享内存,如果有则删除旧的
shmid = shmget((key_t)key, 0, 0);
if (shmid != -1)
{
printf("Delete shmid=%d \n", shmid);
shmctl(shmid, IPC_RMID, NULL); // 删除已经存在的共享内存
}
}
//返回头地址
bool ShmFIFO::ShmOpen(int key, int blksize, int blocks)
{
int shmid;
this->ShmClose();
//1. 查看是否已经存在共享内存,如果有则删除旧的
shmid = shmget((key_t)key, 0, 0);
if (shmid == -1)
{
return this->ShmInit(key, blksize, blocks);
}
//2.连接共享内存
m_shmhead = shmat(shmid, (void*)0, 0); //连接共享内存
if(m_shmhead == (void*)-1)
{
perror("shmat");
}
//3. 填充控制共享内存的信息
m_payload = (char *)((shmhead_t *)m_shmhead + 1); //实际负载起始位置
m_open = true;
return true;
}
void ShmFIFO::ShmClose(void)
{
if(m_open)
{
shmdt(m_shmhead); //共享内存脱离
m_shmhead = NULL;
m_payload = NULL;
m_open = false;
}
}
void ShmFIFO::ShmWrite(const void *buf)
{
shmhead_t *pHead = (shmhead_t *)m_shmhead;
sem_wait(&pHead->sem_full); //是否有资源写? 可用写资源-1
sem_wait(&pHead->sem_mutex); //是否有人正在写?
//memset(m_payload + (pHead->wr_index) * (pHead->blksize), 0, pHead->blksize);
memcpy(m_payload + (pHead->wr_index) * (pHead->blksize), buf, pHead->blksize);
pHead->wr_index = (pHead->wr_index+1) % (pHead->blocks); //写位置偏移
sem_post(&pHead->sem_mutex); //解除互斥
sem_post(&pHead->sem_empty); //可用读资源+1
}
void ShmFIFO::ShmRead(void *buf)
{
shmhead_t *pHead = (shmhead_t *)m_shmhead;
sem_wait(&pHead->sem_empty); //检测写资源是否可用
sem_wait(&pHead->sem_mutex);
//memset(buf, 0, sizeof(buf));
memcpy(buf, m_payload + (pHead->rd_index) * (pHead->blksize), pHead->blksize);
//memset(m_payload + (pHead->rd_index) * (pHead->blksize), 0, pHead->blksize);
//读位置偏移
pHead->rd_index = (pHead->rd_index+1) % (pHead->blocks);
sem_post(&pHead->sem_mutex); //解除互斥
sem_post(&pHead->sem_full); //增加可写资源
}
测试案例
共享内存写端
typedef struct user //定义用户数据包体
{
char UserName[32];
char PassWord[32];
}USER_T;
int main(void)
{
ShmFIFO shm(1234, sizeof(USER_T), 3);
USER_T user1 = {"admin", "123456"};
USER_T user2 = {"lili", "123456"};
USER_T user3 = {"tom", "123456"};
int n = 6;
while(n)
{
shm.ShmWrite(&user1);
printf("ShmWrite success \n");
sleep(1);
shm.ShmWrite(&user2);
printf("ShmWrite success \n");
sleep(1);
shm.ShmWrite(&user3);
printf("ShmWrite success \n");
sleep(1);
}
return 0;
}
共享内存读端
typedef struct user //定义用户数据包体
{
char UserName[32];
char PassWord[32];
}USER_T;
int main(void)
{
USER_T user;
ShmFIFO shm(1234, sizeof(USER_T), 3);
while(1)
{
memset(&user, 0, sizeof(USER_T));
shm.ShmRead(&user);
printf("ShmRead success\n");
printf("UserName = %s, PassWord = %s\n", user.UserName, user.PassWord);
}
return 0;
}
测试结果
下一篇:
C++高并发服务器设计–线程池封装(七)