在上一篇的文章中总结了线程池的设计使用,本篇文章总结了环形共享内存。两者相辅相成,缺一不可,都是为了后面前置后置服务器做铺垫。
完整的代码文中已经给出,如需整个测试项目,私信发。
目录链接
2021-09-09
复习内容
- 注意头结构体 和 整体结构体。头结构体作为整体结构体的成员,整体结构体和几个操作共享内存的函数作为类的方法和属性,
- 头结构体包括:块大小 总块数 读写索引等基本信息
- 整体结构体包括头部指针 实际负载指针,共享内存的句柄,
4个信号量,区别于单个生产者和消费者2个信号量即可,这边还需要多出两个控制多个生产者之间和多个消费者之间的互斥,代码中注释都写的很详细。
- 类中函数 包含
ShmFifo
构造函数初始化 共享内存和信号量,shmfifo_get
配和信号量和读索引从格子拷贝数据。shmfifo_put
配合信号量和写索引从格子考入数据,还包括销毁和判断的函数。- 注意到环形共享队列的好处,可以同时读和写。
- 注意shmget的第三个参数,如果要创建新的共享内存,需要使用IPC_CREAT,IPC_EXCL,如果是已经存在的,可以使用IPC_CREAT或直接传0,我们常常传入0来判断是否存在了
- shmat 参数注意
10-03修改内容
:
- 外层读写锁 内层互斥锁 那是不是 可以保存索引 和 索引后移 及时释放互斥锁 再进行拷贝 。这样应该会更快 可以多个生产者 或者消费者一起工作。
1基本介绍
共享队列是一台主机通信的最快方式,它的好处区别于消息队列及其他通信它可以自定义存储结构。在高并发的应用场景中,多个客户端同时发送信息,信息发送的速度远远大于处理速度,所以我们常常设计一个共享内存预先把发送来的信息进行存储。
2 环形共享内存的设计
2.1 结构图展示
从下图中我们可以很清楚的看出这个环形共享内存的大致信息,他包含了一个头部的结构体用于存放一些基本的信息(块大小、块总数、读索引、写索引)。后半部分由一块一块相同的信息存储结构构成,用于存放发送来的实际信息。
0,1,2,3表示块的索引号。以及两个用于实际读写的索引下标。
2.2 头结构设计
这里是引用
typedef struct shmhead
{
unsigned int blksize; // 块大小
unsigned int blocks; // 总块数
unsigned int rd_index; // 读索引
unsigned int wr_index; // 写索引
int total;
}shmhead_t;
2.3 整体结构设计
typedef struct shmfifo
{
shmhead_t *p_shm; // 共享内存头部指针
char *p_payload; // 有效负载的起始地址
int shmid; // 共享内存ID 操作的句柄
int sem_mutex; // 用来互斥用的信号量 用于同步读的线程(非读和写间)
int sem_mutex1; // 用来互斥用的信号量 用于同步写的线程
int sem_full; // 用来控制共享内存是否满的信号量
int sem_empty; // 用来控制共享内存是否空的信号量
}shmfifo_t;
2.4 类的设计(声明)
class ShmFifo
{
public:
//构造函数用于初始化,申请共享内存空间,挂载映射,信号量的初始化,头结构变量的确定......
ShmFifo(int key, int blksize,int blocks );
//数据放入共享内存
void shmfifo_put(const void *buf);
//从共享内存取出数据 buf表示的是传出参数
void shmfifo_get(void *buf);
//删除共享内存 包括删除信号量 取消映射 释放内存空间
void shmfifo_destroy();
int shmfifo_isempty();
private:
int key_;//共享内存的键值,是一个整数,可以理解成暗号
int blksize_;//块的数量
int blocks_;//块的大小
shmfifo_t *fifo;//结构体指针
};
2.5 类的定义+注释
代码总体来说难度不大,配合注释比较容易理解,由于对信号量进行了封装所以可能不习惯。
一个需要注意的是这边四个信号量的使用,和多个生产者消费者模型
是一致的。(比较容易错),可以对比互斥量加条件变量实现方式。
封装的一些函数
int sem_d(int semid)
// 删除信号量
int sem_v(int semid)
//信号量++
int sem_p(int semid)
//信号量-- 为负数阻塞
int sem_create(int semid)
//创建信号量
int sem_setval(int semid, int val)
;//设置信号量的初始值
ShmFifo::ShmFifo(int key, int blksize,int blocks )
:key_(key),blksize_(blksize),blocks_(blocks)
{
fifo = (shmfifo_t *)malloc(sizeof(shmfifo_t));//共享内存信息的结构体 由于定义为shmfifo_t * fifo指针 所以开辟空间
/*一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告并且退出*/
assert