Liunx——进程间通信、SystemV共享内存

本文详细介绍了SystemV共享内存在Linux系统中的工作原理,包括物理内存申请、页表映射以及关键的shmget、shmat、shmdt和shmctl函数的使用。通过这些函数,进程间可以高效地共享内存,减少内核干预,提高通信效率。
摘要由CSDN通过智能技术生成

SystemV共享内存

我们上一篇所谈的管道,不管是匿名还是命名,本质都是基于文件的,而下面的System V共享内存是一种用于在Linux系统中进程间共享内存的,是操作系统特地设计的一种通信方式

但本质都是让不同的进程看到同一份资源

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据

原理:

  • 首先,在物理内存中申请一块资源
  • 其次,将这块资源与各个进程的页表建立影视
  • 最后,在共享区中开辟空间并将虚拟地址填充到各自页表的对应位置

进程便看到了同一份物理内存,这块物理内存就叫做共享内存


共享内存示意图

在这里插入图片描述


共享内存数据结构

系统中可能会有大量的进程正在进行通信,因此系统当中就可能存在大量的共享内存,那么操作系统必然要对其进行管理(先描述,再组织)
所以共享内存除了开辟空间之外,系统还要为共享内存维护相关的内核数据结构。

struct shmid_ds {
    struct ipc_perm shm_perm; /* operation perms */
    int shm_segsz; /* size of segment (bytes) */
    __kernel_time_t shm_atime; /* last attach time */
    __kernel_time_t shm_dtime; /* last detach time */
    __kernel_time_t shm_ctime; /* last change time */
    __kernel_ipc_pid_t shm_cpid; /* pid of creator */
    __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
    unsigned short shm_nattch; /* no. of current attaches */
    unsigned short shm_unused; /* compatibility */
    void *shm_unused2; /* ditto - used by DIPC */
    void *shm_unused3; /* unused */
};

当我们申请了一块共享内存后,由于有很多共享内存,所以为了让要实现通信的进程能够看到同一个共享内存,因此每一个共享内存被申请时都有一个key值来确定共享内存的唯一性

对于struct ipc_perm shm_perm;,每个共享内存的key值存储在shm_perm这个结构体变量当中

struct ipc_perm{
	__kernel_key_t  key;
	__kernel_uid_t  uid;
	__kernel_gid_t  gid;
	__kernel_uid_t  cuid;
	__kernel_gid_t  cgid;
	__kernel_mode_t mode;
	unsigned short  seq;
};

共享内存函数

shmget函数

声明

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

返回值

  • 成功,返回一个有效的共享内存标识符(用户层标识符)
  • 失败,返回-1

参数

  • key_t key:表示待创建共享内存在系统当中的唯一标识。一般调用ftok()函数创建

key_t ftok(const char *pathname, int proj_id);
ftok函数是将一个已存在的路径名pathname和一个整数标识符proj_idt通过算法转换成一个key值,在使用shmget函数获取共享内存时,这个key值会被填充进维护共享内存的数据结构当中

  • size_t size:表示待创建共享内存的大小,以字节为单位
  • int shmflg:表示创建共享内存的方式。

关于shmflg
IPC_CREAT:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存;如果存在这样的共享内存,则直接返回该共享内存
IPC_CREAT | IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存;如果存在这样的共享内存,则返回出错

创建或获取共享内存,创建成功后,使用 shmat将其和进程的地址空间关联。

shmat函数

声明

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

返回值

  • 成功,返回一个指针,返回共享内存映射到进程地址空间中的起始地址
  • 失败,返回-1

参数

  • int shmid:表示待关联共享内存的用户级标识符。
  • const void *shmaddr:指定共享内存映射到进程地址空间的某一地址,通常设置为NULL,表示让内核自己决定一个合适的地址位置。
  • int shmflg:标志参数,可以包括一些特定的选项,比如 :SHM_RND和SHM_RDONLY

当不再需要共享内存时,需要使用 shmdt将其去关联

shmdt函数

声明

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

返回值

  • 成功,返回 0
  • 失败,返回-1

参数

  • const void *shmaddr:待去关联共享内存的起始地址,即调用shmat函数时得到的起始地址。

注意
将共享内存段与当前进程脱离不等于删除共享内存,只是取消了当前进程与该共享内存之间的联系。 所以,通常需要在不再需要共享内存时使用 shmctl 来删除共享内存段。

shmctl函数

声明

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

返回值

  • 成功,返回一个非负整数,具体返回值取决于执行的命令
  • 失败,返回-1

参数

  • int shmid:由shmget返回的共享内存标识码
  • int cmd:将要采取的动作(有三个可取值)

IPC_STAT:获取共享内存的状态,将信息写入 buffer 参数指向的结构体中。
IPC_SET: 设置共享内存的状态,通过 buffer参数中提供的信息进行设置。
IPC_RMID:从系统中删除共享内存段。

在这里插入图片描述

  • struct shmid_ds *buf :指向一个保存着共享内存的模式状态和访问权限的数据结构

使用IPC_RMID可以删除共享内存段。删除后,所有附加到该共享内存段的进程将不再能够访问共享内存,但直到所有进程都断开连接,系统才会回收该共享内存。(里面会有一个计数器来统计关联到该共享内存的进程个数)

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值