共享内存
当多个进程需要在其间共享数据时,共享内存提供了一种高效的方式。它允许多个进程将同一块内存映射到它们的地址空间中,使得它们可以直接读写该内存,而不需要通过消息传递或其他形式的通信。
系统接口
在Linux中,使用共享内存需要以下步骤:
- 创建共享内存区域:使用
shmget
系统调用来创建一个共享内存区域,并指定大小和权限。- 连接到共享内存区域:使用
shmat
系统调用将共享内存区域连接到进程的地址空间中,返回指向共享内存的指针。- 使用共享内存:通过使用指针可以直接读写共享内存。
- 分离共享内存:使用
shmdt
系统调用将共享内存从进程的地址空间中分离。- 删除共享内存区域:使用
shmctl
系统调用可以删除共享内存区域。
共享内存是一种强大的进程间通信机制,但它也需要谨慎使用,因为多个进程可以直接修改共享内存中的数据,所以需要通过其他方式(如信号量)来确保数据的正确性和一致性。在编程中,可以使用C语言中的<sys/shm.h>
头文件提供的函数来进行共享内存的操作。
当释放共享内存的时候,要先切断他们的映射关系,再释放共享区
创建共享内存区域 shmget
cpp
//shmget所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
当创建成功后,返回共享内存的编号shmid,进程之间调用同一个共享内存的shmid是相等的
当创建失败后返回-1
key
- 共享内存是操作系统在内存中申请的一块内存空间,操作系统中可能会有大量的共享内存,操作系统为了管理这些共享内存就要用相应的结构来进行描述,每个共享内存都有自己唯一的标识来代表。
- 函数作用: 系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到
cpp
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
pathname
用于产生key_t值的文件名(文件必须存在)
proj_id
的低序8位(不能为0)
size
- size参数用于指明要创建的共享内存的大小,单位为字节。
- 操作系统创建共享内存是以page页为单位的,大小为4KB。
shmflg
shmflg参数用于指明shmget的使用模式。
IPC_CREAT and IPC_EXCL
单独使用
IPC_CREAL
:创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,获取已经存在的共性内存并返回
IPC_EXCL
不能单独使用,一般都要配合IPC_CREAT
IPC_CREAT | IPC_EXCL
:创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,则立马报错返回-- 如果创建成功,对应的shm,一定是最新的
关联共享区域 shmat
当使用共享内存时,需要将其先与要映射的进程进行关联,才可以进行通信
cpp
//shmat所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid
:shmget创建共享内存时的返回值
shmaddr
:指明要关联到的地址处,传入空指针操作系统会自己进行关联。
shmflg
:指明对要关联的共享内存的权限,传入0为读写权限。如果关联成功则返回其对应的虚拟地址,失败返回-1
去除共享关联 shmdt
当要进行删除共享内存的时候,我们需要将其的关联全部去除后,才可以正常删除共享内存
cpp
//shmdt所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
shmaddr
:为共享关联时,返回的虚拟地址成功返回0,失败返回-1
删除共享内存区域
当共享内存的进程退出的时候,我们的共享内存还是存在的,它是随的os的退出而退出,而不是进程退出它就退出的
删除共享区域的方式有两种一种为命令删除
ipcrm -m
另一种为调用系统函数删除
shmctl
ipcrm选项介绍
ipcs表示多个通信资源,选项包括队列(-q),共享内存(-m),信号量(-a)
我们需要查看我们的共享内存时,可以通过
-m
选项来查看
ipcrm -m 加 shmid
可以删除一个共享内存,这里是不可以通过key删除的
key
类比文件的inode
shmid
类比文件的fd
shmctl选项介绍
cpp
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:创建和读取共享进程时的返回值
cmd:对共享内存做操作(cmd选项有多种,其中包括,IPC_STAT 获取当前共享内存属性,IPC_SET 设置共享内存属性,IPC_RMID 标记这个段为释放)
*buf:获取共享内存字段属性,也是包括多种属性(删除时属性为nullptr)
如果函数发生错误返回-1
cpp
int n = shmctl(shmid, IPC_RMID, nullptr);
assert(n != -1);
(void)n;
共享内存特性
- 无需多余拷贝:使用共享内存通信不需要任何接口,只要共享内存被映射到进程地址空间中,进程就能看到共享内存。
- 速度快:共享内存被映射到进程的地址空间中,进程就能看到共享内存,不涉及缓冲区,无需多余拷贝动作,因此共享内存通信速度很快。
- 无保护:使用共享内存通信不需要任何接口,因此共享内存不存在任何保护机制。