目录
共享内存
引入
原理
- 还记得我们的动态库吗,它可以实现内存中只加载一份库,却可以映射到多个进程中
- 我们可以将 [动态库的原理] 和 [通信本质--让不同进程看到同一份资源]结合起来想
- 也就是 -- os自己申请一部分空间,同样映射到多个进程中,也就能实现多个进程访问同一块空间
位置
- 既然是一块空间,当进程访问的时候,就要放在它的地址空间中
- 这部分叫做内存映射区域
如何管理
- 如果有多个进程都在使用这块共享内存,或者有多个共享内存,是不是需要os来管理他们?
- 也就是--先描述,再组织
- 首先,是不是需要统计这块内存被几个进程使用着,以及其他的属性也需要被记录
- 这就需要我们额外的空间来记录这些信息,而这些信息也就描述了这块空间的属性等等
- 所以,共享内存 = 共享内存块 + 对应的内核数据结构
思考原理
在介绍使用方法之前,我们可以自己先来思考一下究竟该如何实现
- 首先,我们要开辟一块空间
- 最重要的是 -- 要保证不同进程可以通过某种方式拿到同样的空间
- 之后就可以对这块空间进行读写
- 但是!!!如果多个进程同时进行io,究竟谁先谁后呢?
- 在不知道对方动作的情况下,很可能导致数据读写并不符合我们的预期
- 最后就是资源泄漏问题,如果当前共享内存已经没有进程访问了,就需要释放空间了
接下来就是正式开始介绍了
使用
ftok() -- 获取key
函数原型
返回值 -- key
- 每个进程通过key来识别和访问共享的系统资源
- 相当于可以通过这个特定的key值找到对应的共享空间(我们要保证通信的双方访问同一块空间)
key的形成
- 由路径名和整数标识符两个参数,通过某个算法形成
- 用于唯一标识一个特定的系统资源
不同进程获得相同key
通过使用相同的路径名和标识符调用ftok()函数,可以实现对同一共享资源的访问
shmget -- 使用key获得共享内存
函数原型
使用示例:
int shmid = shmget(key, SUM_SIZE, IPC_CREAT|IPC_EXCL|0666);
key
用于标识生成的这块共享内存
size
- 共享内存大小
- 一般是页大小的整数倍 (在x86架构的计算机中,通常使用的页大小是4KB(4096字节))
- 如果设置的大小不是整数倍,会浪费空间资源 (因为只能使用页的倍数来开辟空间)
shmflg
控制共享内存段的创建和访问方式
IPC_CREAT
创建新的共享内存
IPC_EXCL
- 确保不覆盖已存在的共享内存(保证返回的是新的共享内存)
- 不可以单独使用
空间的权限
使用八进制数表示
shmflg为0时
示例
这里我们的key没有对应的共享内存块,所以shmid返回了-1:
返回值 -- shmid
- 获取失败,返回-1
- 成功,返回这块共享内存的shmid
key和shmid的关系
在创建或访问共享内存段时,key用于指定共享内存段,而shmid用于后续的操作和访问
也就是 -- key标识共享内存,shmid在shmget()中与key关联,给上层使用
shmid -- 用户层标识符
- 可以被用于其他System V IPC函数(如shmat、shmdt等)来操作和访问共享内存段
key -- 内核层标识符
- 是一个32位的整数值
- 用于在进程间共享内存、信号量和消息队列等系统资源之间进行标识和访问
- 由ftok()根据给定的路径名和标识符生成
- 在shmget函数的调用中用于指定要创建或访问的共享内存段,也就是将key和shmid关联起来
shmat -- 连接进程和共享内存
函数原型
shmid
将要连接的共享内存段的用户级标识符
shmaddr
- 指定共享内存段的附加地址
- 通常将其设置为NULL,表示由os自动选择合适的地址
shmflg
- 用于指定连接方式的标识位
- 通常为0,表示以默认的方式连接共享内存
- 在默认情况下,连接是读写的,而且系统会选择合适的地址来附加共享内存段
返回值
- 返回共享内存段的起始地址
- 可以将共享内存块想象成一个特定大小的字符串,起始地址也就是字符串的起始地址
- 如果失败,返回-1
shmdt -- 使进程和共享内存脱离连接
函数原型
shmaddr
指向共享内存段的起始地址(也就是shmat()的返回值)
作用
- 将共享内存段从调用进程的地址空间中分离
- 分离后,进程将无法继续访问和操作该共享内存段中的数据
- 在使用共享内存段后,应及时调用shmdt函数将其分离,以释放系统资源并确保正确的内存管理
注意点 -- 共享内存的生命周期
- 调用shmdt函数只是分离共享内存段,并不会删除或销毁该共享内存段
- 因此可以知道共享内存的生命周期不是随进程的,而是随os
返回值
- 成功分离共享内存段时,shmdt函数返回0
- 失败时,返回-1
shmctl -- 控制共享内存
函数原型
用于执行各种共享内存段的操作
shmid
共享内存段的用户级标识符
cmd
指定要执行的操作的命令的标识符
buf
- 指向struct shmid_ds类型的结构体的指针(这个结构体在<sys/shm.h>中定义)
- 用于传递或接收与共享内存段相关的信息
struct shmid_ds类型的结构体
- 这个也就是前面说的 -- 用于描述共享内存的数据结构
- 当我们想定义它的属性,就可以通过这个来定义,然后传递给shctl函数
(当我们执行删除操作时,是不需要这个结构体的,直接传入nullptr即可)
ipcrm -m + shmid
在命令行中使用
从系统中删除对应的共享内存标识符