共享内存的原理
- 在物理内存中开辟一块空间;
- 不同进程通过页表将该空间映射到字节的进程虚拟地址空间中;
- 不同进程通过操作自己进程虚拟地址空间当中的虚拟地址,来操作共享内存;
使用共享内存步骤:
- 创建共享内存;
- 附加,将进程附加该共享内存上(将进程虚拟地址和物理地址通过页表建设映射关系);
- 分离,将虚拟地址和物理地址的映射关系从页表中删除
共享内存映射到物理地址空间时 ,是映射在共享区中(在栈区和堆区中间)
共享内存接口:
1.创建或者获取共享内存
key_t ftok(const char* pathname, int proj_id) 参数:
- pathname:随意填写一个已经存在的文件路径(不存在则报错)
- proj_id:项目id,只用到八个比特位,但传递时需传一个整型
返回值:共享内存标识符,这个返回值本质上是一个32 位的十六进制数,类似一个地址
- key_t称为IPC(叫进程间通信)通信标识符,通过ftok函数获取
- ftok函数的作用就是通过两个给出的参数算出一个IPC标识符,
该标识符在整个操作系统中是唯一的(key_t是一个16进制数) - 也可以不用该函数计算,我们自己可以直接指定
- 算出的IPC标识符在整个操作系统中是唯一的
int shmget(key_t key, size_t size, int shmflg)
参数:
- key:共享内存标识符(当前共享内存的名字)要通过ftok函数获取标识符
- size:共享内存的大小;
- shmflg:共享内存的属性信息
返回值:
- 成功:返回共享内存的操作句柄,通过标识符找到共享内存,找到后通过操作句柄操作共享内存
IPC_CREAT | 共享内存不存在则创建 |
---|
IPC_EXCL | 一定要搭配IPC_CREAT使用,搭配使用后的含义:如果共享内存存在则报错,不存在则创建 |
搭配使用是要获得自己创建的共享内存,不使用别人的 共享内存创建时也需要设置权限信息,需要按位或上共享内存的权限(八进制数字)表示
2.附加接口:将共享内存附加到当前内存上 void* shmat(int shmid, const void* shaddr, int shmflg) at是attach附加的意思
参数:
- shmid:共享内存操作句柄
- shaddr:将共享内存附加到共享区当中的哪一个地址;
一般是传递NULL值,让操作系统分配 - shmflg以何种权限附加:
0:可读可写 SHM_RDONLY:只读
返回值:
- 成功:返回附加的虚拟地址
- 失败:返回NULL
3.分离(两个函数)
将共享内存从进程中分离出来,分离时需告诉shmdt函数刚附加共享内存到进程后,进程虚拟地址的位置
shmdt函数 int shmdt(const void* shmaddr) dt代表detach
参数:
4.删除共享内存:
shmctl函数 int shmctl(int shmid, int cmd, struct shmid_ds* buf)
参数:
- shmid:共享内存操作句柄
- cmd:用传输的值告诉shmctl函数完成什么事情
IPC_SET:设置共享内存属性信息,通过第三个参数设置(该参数是输入型参数) IPC_STAT:获取共享内存属性信息,通过第三个参数获取(出参) IPC_RMID:删除共享内存,第三个参数传递NULL - buf:共享内存数据结构buf
函数使用: 左边先写,右边再读
共享内存的特性:
- 共享内存是覆盖写的方式,读的时候是拷贝(实际上是数据访问)
- 我们写操作在将字符串写入共享内存后,写操作进程结束,在多次读取依旧能多次读取成功;
所以共享内存声明周期跟随操作系统内核,不主动删除则一直存在
删除代码:
其它知识点
执行写操作后,执行ipcs命令有三段输出:消息队列,共享内存,信号量
ipcs –m:只输出共享内存信息
key | 共享内存标识符 |
---|
shimd | 共享内存操作句柄 | owner | 内存创建者 | perms | 内存权限 | bytes | 内存大小 | nattch | 附加进程数量 | statu | 没有显式表示该共享内存正常 |
|