首页 > linux进程间通信:system V 共享内存

linux进程间通信:system V 共享内存

文章目录

        • 思维导图如下
        • 通信原理
        • 优势
        • 运行流程
        • 编程接口
        • 编程实例

思维导图如下

在这里插入图片描述

通信原理

  • 多个进程共享物理内存的同一块区域(通常称之为“段”:segment)
  • 抛弃了内核态消息转存处理的过程,让两个进程直接通过一块内存进行通信

我们普通的像PIPE,FIFO,消息队列等的通信方式如下图:

在这里插入图片描述

这种方式的通信不论读写,都需要内核态(系统调用 read,write,pipe,mkfifo,msgget,msgsnd,msgrcv等)的介入,而且都需要经过数据从虚拟地址空间到物理地址空间的拷贝。

而共享内存的通信方式则都避免了以上的通信问题,直接为两个进程开辟相同的内存空间进行数据交互。

在这里插入图片描述

优势

  • 减少了内存的拷贝(从用户拷贝到内核,从内核拷贝到用户)
  • 减少了2次系统调用(系统调用比较消耗性能,因为CPU处理系统调用时需要从用户态切换到内核态),提高了系统性能

运行流程

  • 获取共享内存对象的ID
  • 将共享内存映射至本进程虚拟内存空间的某个区域(每个用户进程操作系统都有3G的虚拟进程空间)
  • 不同进程对这块内存进行读写、传输数据
  • 当进程不再使用这块共享内存时,解除映射关系
  • 当没有进程需要共享内存的时候,则删除该共享内存

编程接口

  • 获取共享内存的对象ID ,创建或打开一个共享内存对象

    a. 头文件

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

    c. 函数参数

    • key IPC对象的键值,一般为IPC_PRIVATE 或者ftok返回的key值
    • size 共享内存的大小,一般为物理内存页(4K)的整数倍
    • shmflg

      IPC_CREAT :如果不存在指定的key值,那么就创建一个

      IPC_EXCL: 若key值指定的内存存在,且指定了IPC_CEAT,则回复EXIST错误

      IPC_HUGETLB 使用巨页(huge page)

    d. 返回值:共享内存的标识ID

  • 映射共享内存:

    a. 头文件

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

    c. 功能:将shmid标识的共享内存引入到当前进程的虚拟地址空间

    d. 函数参数:

    • shmid 共享内存的IPC对象ID
    • shmaddr

      若为NULL:共享内存会被attach到一个合适的虚拟地址空间,建议使用NULL

      不为NULL:系统会根据参数以及地址边界对齐等分配一个合适的地址
    • shmflg

      IPC_RDONLY:附加只读权限,不指定的话返回默认是读写权限

      IPC_REMAP:替换位于shmaddr处的任意既有映射(共享内存的段或者内存映射)

      SHM_RND:将shmaddr四舍五入为SHMMLBA字节的倍数

    e. 返回值:共享内存段的地址

  • 解除共享内存映射

    a. 头文件

    b. int shmdt(const void * shmaddr);

    c. 功能:解除内粗映射,将共享内存分离出当前进程的地址空间

    d. 函数参数:

    • shmaddr 共享内存地址

    e. TIPS:

    • 通过fork创建的子进程会继承父进程所附加的共享内存,父子进程可以通过共享内存进行IPC通信,在exec系统调用中,所有附加的共享内存段都会被分离
    • 函数shmdt仅仅是使进程和共享内存脱离关系,将共享内存的引用计数是减1
    • 当共享内存的引用计数为0的时候,调用shmctl的IPC_RMID命令才会删除共享内存
  • 设置共享内存属性

    a. 头文件

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

    c. 函数功能:获取/设置共享内存对象属性

    d. 函数参数

    - shmid 共享内存对象的ID

    - cmd:

    IPC_RMID :删除共享内存及关联的shmid_ds数据结构

    IPC_STAT: 将该共享内存关联的shmid_ds数据结构拷贝到参数buf中

    IPC_SET: 使用buf中的数据更新与该共享内存对象相关联的shmid_ds

    IPC_INFO:获取系统共享内存相关的信息

    IPC_LOCK: 将一个共享内存段锁进内存,防止被swap出去

    IPC_UNLOCK: 将一个共享内存解锁

  • shmid_ds *buf数据结构如下

    struct shmid_ds { struct ipc_perm  shm_perm;     /* operation permissions */int              shm_segsz;    /* size of segment in bytes */pid_t            shm_lpid;     /* pid of last shm op */pid_t            shm_cpid;     /* pid of creator */short            shm_nattch;   /* # of current attaches */time_t           shm_atime;    /* last shmat() time*/time_t           shm_dtime;    /* last shmdt() time */time_t           shm_ctime;    /* last change by shmctl() */void            *shm_internal; /* sysv stupidity */};
    

编程实例

写端shm_write.c:

#include
#include 
#include 
#include 
#include 
#include 
#include int main()
{ //key_t key = ftok("./",111);key_t key = 12345;//根据key值生成共享内存对象的唯一标识int shm_id = shmget(key,4096,IPC_CREAT|0666);//将当前进程加入共享内存,这里设置共享内存地址为NULL时//系统会自动为当前进程分配一个合适的内存空间,并返回共享内存的地址char *shm_p = shmat(shm_id , NULL, 0);memset (shm_p,0,4096);//从标准输入获取内容到共享内存的地址fgets(shm_p,4096,stdin);//等待输入完成,删除共享内存sleep(10);//当前进程创建的共享内存引用计数为0的时候,删除共享内存shmctl(shm_id,IPC_RMID,NULL);return 0;
}

读端shm_read.c

#include
#include 
#include 
#include 
#include 
#include 
#include int main() { 
//    key_t key = ftok("./",111);key_t key = 12345;int shm_id = shmget(key, 4096, 0666);//和写端访问到了相同的共享内存区域,并获取内容存放到指针变量char *shm_p = shmat(shm_id , NULL, 0);printf("From SHM: %s
",shm_p);//删除当前进程与共享内存的映射关系,同时共享内存的引用计数减一shmdt(shm_p);return 0;
}

通过命令ipcs -m可以查看系统共享内存

在这里插入图片描述

需要先执行写入,再去运行读端读出;以上输出如下:

在这里插入图片描述

更多相关:

  • 更多内容,欢迎关注微信公众号:全菜工程师小辉~前言在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理。这篇博客将针对第三个原因,进行更详细的讲解。首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并且这两个技术并不是等价的。零拷贝零拷贝是指避免在用户态(User-space)...

  • 一、预备知识—程序的内存分配  一个由c/C++编译的程序占用的内存分为以下几个部分  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器...

  • 我的爱机是一台ThinkPad T420,原装三星DDR 1333 4G内存一根,还剩一根内存位置,最近趁京东6.18促销,准备增加一根物理内存。为了确保兼容性,觉得仍然选购DDR 1333 4G内存,于是购买了金士顿这款,比如DDR3 1600的还贵。 这个安装过程完全参照该内存的网页提示进行 这里简单记录一下,以备...

  • 陪伴我多年的老本ThinkPad T420渐渐垂垂老矣, 我想更新一下可以更新的部分, 比如将2.5寸HDD更换为SSD, 将单条4G内存再增加一根, 凡此种种想法, 可能最后归结为如何获取该笔记本的硬件配置信息, 在windows下面使用鲁大师之类的检测软件, 也许很好搞定,但是在Ubuntu 14.04平台上如果办到呢? 很简单...

  • 一.内存错误出现的场景 这几天在重构ATS插件代码的过程中遇到了烦人的内存泄露问题, 周五周六连续两天通过走查代码的方法,未能看出明显的导致内存错误的代码, 同时也觉得C和C++混合编程得到一个动态库, 在一个.cpp主文件中,即用new又用malloc来动态分配内存, 可能会导致内存错误.后来网上调研和查资料发现, new和mal...

  • 一、首先是安装VMWare tools   安装过程可参考:http://www.cnblogs.com/jiu0821/p/7559949.html   二、解决安装VMWare tools后/mnt中有hgfs但没共享文件 前提:在虚拟机软件中设置了共享目录 此时在linux中进入 /mnt/hgfs 文件夹,但发现共享的文件没...

  • Windows 2000/XP/2003版本的操作系统提供了默认共享功能,这些默认的共享都有“$”标志,意为隐含的,包括所有的逻辑盘(C$,D$,E$……)和系统目录Winnt或Windows(admin$)。 带来的问题     微软的初衷是便于网管进行远程管理,这虽然方便了局域网用户,但对我们个人用户来说这样的设置是不安全的。...

  • 文章目录思维导图通信原理优势POSIX 共享内存 编程接口编程案例 思维导图 之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存 POSIX 同样提供共享内存的接口,基本原理和system V的共享内存是一样的。 通信原理 多个进程共享物理内存的同一块区域(通常称之...