C++高并发服务器设计--共享内存封装(六)

共享内存封装设计
一、共享内存由两个部分组成共享内存头部+共享内存数据区

共享内存头部定义

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++高并发服务器设计–线程池封装(七)

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C君莫笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值