linux系统之----共享内存
1.什么是共享内存
共享内存(Shared Memory)是操作系统提供的一种 最高效 的进程间通信(IPC)机制。它允许多个进程 直接访问同一块物理内存区域,无需通过内核中转数据,从而避免了数据拷贝,速度极快。
2.共享内存原理
这里结合老师的图片来理解一下,可以简单理解为操作系统开一块内存区域作为共享内存,这块内存区域可以被多个进程访问,之后两个进程(进程A和进程B)通过页表将共享内存映射到自己的虚拟地址空间。这意味着每个进程都有一个虚拟地址,指向同一块物理内存。最后当所有进程都不再需要共享内存时,操作系统会回收这块内存。
3.创建共享内存
这里我们要介绍一个函数shmget,
这里我们先解释一下shmget函数里面的三个参数
key:
这是一个
key_t
类型的值,用于标识共享内存段。它可以是一个特定的值,也可以是IPC_PRIVATE
,后者会创建一个私有的共享内存段,不能被其他进程访问,除非它们明确知道这个段的标识符。
size:
这是共享内存段的大小,以字节为单位。这个大小必须与系统页面大小对齐,通常是 4096 字节的倍数。
shmflg:
这是一个权限标志,用于设置共享内存段的访问权限。它通常是一个八进制数,由
IPC_CREAT
(如果不存在则创建共享内存段)、IPC_EXCL
(与IPC_CREAT
一起使用,如果共享内存段已存在则失败)和一组权限位(如0666
或0644
)组成。
我们看一下原文:
补充说明一些内容:
(1)
IPC_CREAT单独:如果创建的共享内存不存在,创建之。如果存在,直接获取它
IPC_EXCL:不能单独使用没有意义
IPC_CREAT | IPC_EXCL:如果共享内存不存在 创建之,如果已经存在 出错返回!
如果成功,返回的就是全新的shm!
(2)
这个key值是用户自己传入的,也许有人会疑惑为什么要用户自己传入呢?原因就是要保证唯一性:即key
值用于在系统中唯一标识一个共享内存段。如果两个进程想要访问同一个共享内存段,它们需要使用相同的 key
值来引用它。手动传入 key
值可以确保进程能够找到正确的共享内存段。如果系统自动生成 key
值,可能会在不同的进程或会话中生成相同的 key
值,从而导致冲突。
那么用户是如何得到Key值的呢?这里就要引入另外一个函数ftok()
4.key值的获取
我们看一下ftok函数的细节:
那这个函数是如何保证产生的Key值是相同的呢?原因就是在一个文件下,假设我定义如下便变量:
char* pathname="/tmp";
int pro_id=0x66;
那么,既然函数传的参数都是一样的,那返回值也一定是相同的,如此,我们得到了这个相同的Key值,之后再将它传入shmget函数中!
5.映射
现在我们已经拿到共享内存了,那么下一步便是将共享内存段映射到进程的地址空间,即shmat函数(shared memory attach)
参数说明
shmid:
这是共享内存段的标识符,由
shmget
函数返回。它是一个非负整数,用于唯一标识一个共享内存段。
shmaddr:
这是一个指针,指定共享内存段在进程地址空间中的首选映射地址。通常设置为
NULL
,表示让系统选择一个合适的地址。
shmflg:
这是一个标志,用于控制共享内存的映射属性。它可以是以下值的组合:
SHM_RDONLY
:将共享内存段映射为只读。SHM_RND
:将共享内存段映射到一个由shmaddr
参数指定的地址的某个倍数。IPC_CREAT
:如果共享内存段不存在,则创建它(通常与shmget
函数一起使用)。
6.脱离
如果我们想解除(或分离)共享内存段与进程地址空间之间映射关系,那么我们可以用shmdt函数
shmaddr:
这是一个指针,指向之前通过
shmat
函数映射到进程地址空间的共享内存段的起始地址。
注意事项
1)解除映射后,进程将不再能通过原来的地址访问共享内存。如果需要再次访问,必须重新映射。
2)shmdt
函数不会删除共享内存段。共享内存段仍然存在于系统中,直到所有映射它的进程都解除映射,并且通过 shmctl
函数显式删除。
3)在多线程环境中,如果多个线程访问同一个共享内存段,每个线程都需要调用 shmdt
来解除映射。
7.控制
如果我们想控制共享内存段的 System V IPC(进程间通信),可以用shmctl函数,它提供了多种操作,包括获取共享内存段的信息、删除共享内存段等。
shmid:
这是共享内存段的标识符,由
shmget
函数返回。它是一个非负整数,用于唯一标识一个共享内存段。
cmd:
这是一个命令,指定对共享内存段执行的操作。常见的命令包括:
IPC_STAT
:获取共享内存段的状态信息,并将结果存储在buf
参数指向的结构中。IPC_SET
:设置共享内存段的权限和所有者信息,使用buf
参数指向的结构提供新值。IPC_RMID
:删除共享内存段,释放所有相关资源。
buf:
这是一个指向
shmid_ds
结构的指针,用于存储或设置共享内存段的状态信息。具体使用取决于cmd
参数的值。
注意事项
使用 IPC_RMID
删除共享内存段时,需要确保所有进程都已解除映射(通过 shmdt
函数)。
8.比较key和shmid
key vs shmid
key:只有内核使用,用来标识shm的唯一性,是用于查找或创建 IPC 资源的关键字,它是一个抽象的概念,用于标识资源
shmid:给用户使用,用来进行访问shm,shmid
是由操作系统分配的,用于唯一标识一个共享内存段的整数。它是具体的,用于操作系统内部管理和操作共享内存段。
接下来我们再用共享内存的知识写一下客户端和服务器那个小项目~