【Linux】共享内存

共享内存

当多个进程需要在其间共享数据时,共享内存提供了一种高效的方式。它允许多个进程将同一块内存映射到它们的地址空间中,使得它们可以直接读写该内存,而不需要通过消息传递或其他形式的通信。

系统接口

在Linux中,使用共享内存需要以下步骤:

  1. 创建共享内存区域:使用shmget系统调用来创建一个共享内存区域,并指定大小和权限。
  2. 连接到共享内存区域:使用shmat系统调用将共享内存区域连接到进程的地址空间中,返回指向共享内存的指针。
  3. 使用共享内存:通过使用指针可以直接读写共享内存。
  4. 分离共享内存:使用shmdt系统调用将共享内存从进程的地址空间中分离。
  5. 删除共享内存区域:使用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;

共享内存特性

  • 无需多余拷贝:使用共享内存通信不需要任何接口,只要共享内存被映射到进程地址空间中,进程就能看到共享内存。
  • 速度快:共享内存被映射到进程的地址空间中,进程就能看到共享内存,不涉及缓冲区,无需多余拷贝动作,因此共享内存通信速度很快。
  • 无保护:使用共享内存通信不需要任何接口,因此共享内存不存在任何保护机制。
相关推荐
我们的五年1 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
爱吃青椒不爱吃西红柿‍️21 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
IT果果日记22 分钟前
ubuntu 安装 conda
linux·ubuntu·conda
Python私教25 分钟前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
羑悻的小杀马特38 分钟前
环境变量简介
linux
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
运维&陈同学1 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
是阿建吖!1 小时前
【Linux】进程状态
linux·运维
hzyyyyyyyu1 小时前
内网安全隧道搭建-ngrok-frp-nps-sapp
服务器·网络·安全
明明跟你说过2 小时前
Linux中的【tcpdump】:深入介绍与实战使用
linux·运维·测试工具·tcpdump