共享内存 system V共享 分析与实现

system V共享

共享内存区是最快的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 */
};

原理

  1. 在物理内存当中开辟一段空间
  2. 各个进程通过页表结构将该内存映射到自己的虚拟地址空间当中的共享区
  3. 各个进程之间的通信是通过修改自己的虚拟地址空间当中的共享区来完成

使用共享内存

  1. 创建共享内存
int shmget(key_t key, size_t size, shmflag)
    key:共享内存的标识符
    size:共享内存的大小
    shmflag:
        IPC_CREAT:如果共享内存不存在,则创建共享内存,如果已经存在,则返回共享内存
        IPC_EXCL | IPC_CREAT:如果共享内存存在了,则使用这一对标志为shmget 函数就会报错按位或上权限,使用 8 进制的数字来进行按位或
  1. 将进程附加到共享内存上去
void*  shmat(int shmid, const void* shmaddr, int shmflag)
    shnid:共享内存的操作句柄
    shuaddr:映射到共享区的地址,都不会去选择,设置为 NULL ,由操作系统来指定将内存映射到共享区的那个地址上
    shmflg:
        0:可读可写
        IPC_RDONLY:只读
返回值:返回映射到那个地址上,可使用这个地址进行读写操作,读写是共享内存
  1. 从共享内存上分离进程
int shudt(const void* shmaddr)
    shmaddr:shmat 返回的地址
    返回值:
        0:成功
        -1:失败
  1. 共享内存销毁
int shuctl(int shmid, int cmd, struct shmid_ds* buf)
    shnid:共享内存操作句柄
    cmd:
        销毁:
            IPC_RMID:删除共享内存,标记共享为删除状态
        获取共享内存信息:
            IPC_STAT:获取共享内存状态,需要搭配shmid_ds 共同使用
    buf:当需要获取共享内存信息时,cmd 传的是  IPC_STAT ,同时需要传一个struct shmid_ds 对象的地址,shmctl 在函数
    内部结构体的内容进行填充,然后返还给调用,buf 是一个出参

特性

  1. IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核
  2. 不同进程对共享内存区域进行读的时候,并不会抹除物理内存当中的值,写入数据方式为覆盖
  3. 共享内存不带有同步互斥功能

命令

查看:
    ipcs 可以查看共享内存,消息队列,信号量的资源
    ipcs -m 只看共享内存
删除:
    ipcrm -m [shmid]

如果删除一个有进程附加的共享内存,操作系统的做法是:

    先标记当前的共享内存为 destroy 状态
    将 key 设置为 0x00000000,表示当前的共享内存不能被其他进程附加,同时释放内存
    当附加的进程释放该共享内存,操作系统就会立即将该共享内存保存的结构释放掉
    
    风险:
    由于删除共享内存,操作系统释放了内存,但还是有进程附加到内存上,有可能导致该附加的进程在访问这个非法的地址时崩溃
发布了47 篇原创文章 · 获赞 108 · 访问量 4726

猜你喜欢

转载自blog.csdn.net/qq_44759710/article/details/104359068