模型

#include <unistd.h>         //for fstat()
#include <sys/types.h>      //for fstat()
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
shm_open()            //创建/获取共享内存fd
ftruncate()           //创建者调整文件大小
mmap()                //映射fd到内存
munmap()              //去映射fd
shm_unlink()          //删除共享内存          

shm_open

//创建/获取共享内存的文件描述符,成功返回文件描述符,失败返回-1
//Link with -lrt.
int shm_open(const char *name, int oflag, mode_t mode);

oflag

  • Access Mode:
  • O_RDONLY以只读的方式打开共享内存对象
  • O_RDWR以读写的方式打开共享内存对象
  • Opening-time flags(Bitwise Or):
  • O_CREAT 表示创建共享内存对象,刚被创建的对象会被初始化为0byte可以使用ftuncate()调整大小
  • O_EXCL用来确保共享内存对象被成功创建,如果对象已经存在,那么返回错误
  • O_TRUNC表示如果共享内存对象已经存在那么把它清空

mode: eg,0664 etc

ftruncate()

//调整fd指向文件的大小,成功返回0,失败返回-1设errno
//VS truncate()
int ftruncate(int fd, off_t length);

如果原文件大小>指定大小,原文件中多余的部分会被截除

int res=ftruncate(fd,3*sizeof(Emp));//要用sizeof,且是Emp(类型)不是emp(对象)
if(-1==res)perror("ftruncate"),exit(-1);

fstat()

//获取文件状态,成功返回0,失败返回-1设errno
//VS stat()
int lstat(const char *pathname,     struct stat *buf);
int fstat(int fd, struct stat *buf);

buf:stat类型的指针

struct stat {dev_t   st_dev;                 /* ID of device containing file */ino_t   st_ino;                 /* inode number */mode_t  st_mode;                /* protection */        八进制            usigned int o%nlink_t st_nlink;               /* number of hard links */uid_t       st_uid;             /* user ID of owner */gid_t       st_gid;             /* group ID of owner */dev_t       st_rdev;            /* device ID (if special file) */off_t       st_size;            /* total size, in bytes */                      ld%blksize_t   st_blksize;         /* blocksize for filesystem I/O */blkcnt_t    st_blocks;          /* number of 512B blocks allocated */struct timespec st_atim;        /* time of last access */   struct timespec st_mtim;    /* time of last modification */     ld%,秒struct timespec st_ctim;    /* time of last status change */
};
//eg:
st_mode=100664      //100是文件类型//664是权限, 通过100664和0777BitwiseAND得到
st_mtime=1462787968 //秒

mmap()

//映射文件或设备到进程的虚拟内存空间,映射成功后对相应的文件或设备操作就相当于对内存的操作
//映射以页为基本单位,文件大小, mmap的参数 len 都不能决定进程能访问的大小, 而是容纳文件被映射部分的最小页面数决定传统文件访问
//要求对文件进行可读可写的的打开!!!
//成功返回映射区的指针,失败返回-1设errno
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);   //prot:protection, 权限

addr:映射的起始地址, 如果为NULL则由kernel自行选择->最合适的方法
length:映射的区域长度
prot:映射内存的保护权限

  • PROT_EXEC表示映射的内存页可执行
  • PROT_READ表示映射的内存可被读
  • PROT_WRITE表示映射的内存可被写
  • PROT_NONE表示映射的内存不可访问

flags

must include one of :

  • MAP_SHARED表示共享这块映射的内存,读写这块内存相当于直接读写文件,这些操作对其他进程可见,由于OS对文件的读写都有缓存机制,所以实际上不会立即将更改写入文件,除非带哦用msync()或mumap()
  • MAP_PRIVATE表示创建一个私有的copy-on-write的映射, 更新映射区对其他映射到这个文件的进程是不可见的

can be Bitwise ORed:

  • MAP_32BIT把映射区的头2GB个字节映射到进程的地址空间,仅限域x86-64平台的64位程序,在早期64位处理器平台上,可以用来提高上下文切换的性能。当设置了MAP_FIXED时此选项自动被忽略
  • MAP_ANONYMOUS映射不会备份到任何文件,fd和offset参数都被忽略,通常和MAP_SHARED连用
  • MAP_DENYWRITEignored.
  • MAP_EXECUTABLEignored
  • MAP_FILE用来保持兼容性,ignored
  • MAP_FIXED不要对addr参数进行处理确确实实的放在addr指向的地址,此时addr一定时页大小的整数倍,
  • MAP_GROWSDOWN用在栈中,告诉VMM映射区应该向低地址扩展
  • MAP_HUGETLB (since Linux 2.6.32)用于分配"大页"

fd: file decriptor
offset: 文件中的偏移量

void* pv=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);
if(MAP_FAILED==pv)perror("mmap"),exit(-1);

映射机制小解

  • mmap()就是建立一个指针,这个指针指向页高速缓存的一页,并假设这个页有我们想要访问的文件内容(此时都在虚拟地址空间),当然,这个页描述符会自动的加入的调用进程的页表中。当我们第一次使用这个指针,去访问这个虚拟地址的页时,发现这个页还没有分配物理页框,没有想要的文件,引起缺页中断,系统会把相应的(fd)文件内容放到高速缓存的物理页框(此时才会有对物理地址空间的读写)
  • 映射过程中使用的文件相当于药引子,因为所有进程都是可以通过VFS访问磁盘文件的,所以这个文件相当于对映射内存的一个标识,有了这个位于磁盘的药引子,很多进程都可以根据它找到同一个物理页框,进而实现内存的共享,并不是说就在磁盘上读写
  • 页高速缓存的内容不会立即写到磁盘中,会等几秒,这种机制可以提高效率并保护磁盘
  • 只要内存够大,页高速缓存的内容就会一直存在内存中,以后再有进程对该缓存页的内容访问的需求,就不需要从磁盘中搜索,直接访问缓存页(把这个页加入到进程的页表)就行
  • mmap()是系统调用,使用一次的开销比较大,但比文件读写的read()/write()进行内核空间到用户空间的数据复制要快,通常只有需要分配的内存>128KB(malloc一次分配33page就是128KB)的时候才会使用mmap()
  • /shm是一个特殊的文件系统,它不对应磁盘中的区域,而是内存中,所以使用mmap()在这个文件系统中创
  • /proc 不占用任何磁盘空间
  • linux采用的是页式管理机制。对于用mmap()映射普通文件来说,进程会在自己的地址空间新增一块空间,空间大小由mmap()的len参数指定,注意,进程并不一定能够对全部新增空间都能进行有效访问。进程能够访问的有效地址大小取决于文件被映射部分的大小。
  • 简单的说,能够容纳文件被映射部分大小的最少页面个数决定了进程从mmap()返回的地址开始,能够有效访问的地址空间大小。超过这个空间大小,内核会根据超过的严重程度返回发送不同的信号给进程。
  • 经过内核!=在内核空间和用户空间来回切换!=在内核空间和用户空间传递复制的数据
  • 页是内存映射的基本单位, 可以理解为实际分配给物理内存的基本单位, 但不是数据操作的基本单位;
  • 页机制是操作系统和CPU约定好的一种方式,OS按照页给CPU按页发虚拟地址,CPU按页解析并处理
  • 操作系统(包括Linux)大量使用的缓存的两个原理:
    * CPU访问内存的速度远远大于访问磁盘的速度(访问速度差距不是一般的大,差好几个数量级)
    * 数据一旦被访问,就有可能在短期内再次被访问(临时局部原理)
  • 页高速缓存(page cache)是个内存区域,是Linux 内核使用的主要磁盘高速缓存,在绝大多数情况下,内核在读写磁盘时都引用页高速缓存,新页被追加到页高速缓存以满足用户态进程的读请求,如果页不在高速缓存中,新页就被加到高速缓存中,然后就从磁盘读出的数据填充它,如果内存有足够的空闲空间,就让该页在高速缓存中长期保留,使其他进程再使用该页时不再访问磁盘, 即磁盘上的文件缓存到内存后,它的虚拟内存地址可以有多个,但是物理内存地址却只能有一个
  • 我们要读写磁盘文件时,实质是对页高速缓存进行读写,所以无论读写,都会首先检查页高速缓存有没有这个文件对应的页,如果有,就直接访问,如果没有,就引起缺页中断,给OS发信号,让它把文件放到高速缓存再进行读写,这个过程不经过内核空间到用户空间复制数据
  • OS中的页机制,对应到硬件中可不一定在主存中,也可以是高速缓存etc,但不会是磁盘,因为磁盘文件的地址和内存不一样,不是按照32位编址的,而是按照ext2 etc方式编址的,需要使用文件管理系统,在Linux中使用VFS和实际文件管理系统来管理文件,所以对于Linux,有两个方式使用系统资源:VMM,VFS,前者用来管理绝大部分的内存,后者用来管理所有的文件和部分特殊文件系统(eg:/shm是内存的一块区域)
  • page cache可以看作二者的桥梁,把磁盘文件放到高速缓存,就可以按照内存的使用方式使用磁盘的文件,使用完再释放或写回磁盘page cache中的页可能是下面的类型:
    * 含有普通文件数据的页
    * 含有目录的页
    * 含有直接从块设备(跳过文件系统层)读出的数据的页
    * 含有用户态进程数据的页,但页中的数据已经被交换到硬盘
    * 属于他书文件系统文件的页
  • 映射:一个线性区可以和磁盘文件系统的普通文件的某一部分或者块设备文件相关联,这就意味着内核把对区线性中页内某个字节的访问转换成对文件中相应字节的操作
  • TLB(Translation Lookaside Buffer)高速缓存用于加快线性地址的转换,当一个线性地址第一次被使用时,通过慢速访问RAM中的页表计算出相应的物理地址,同时,物理地址被存放在TLB表项(TLB entry),以便以后对同一个线性地址的引用可以快速得到转换
  • 在初始化阶段,内核必须建立一个物理地址映射来指定哪些物理地址范围对内核可用,哪些不可用
  • swap(内存交换空间)的功能是应付物理内存不足的情况下所造成的内存扩展记录的功能,CPU所读取的数据都来自于内存,那当内存不足的时候,为了让后续的程序可以顺序运行,因此在内存中暂不使用的程序和数据就会被挪到swap中,此时内存就会空出来给需要执行的程序加载,由于swap是使用硬盘来暂时放置内存中的信息,所以用到swap时,主机硬盘灯就会开始闪个不同
  • Q:CPU只能对内存进行读写,但又是怎么读写硬盘的呢???A:把数据写入page cache,再经由。。。写入磁盘(包括swap) --《鸟哥》P10
  • 内存本身没有计算能力,寻址之类的都是CPU的事,只是为了简便起见,我们通常画成从内存地址A跳到内存地址B
  • OS是软件的核心,CPU是执行的核心
    * 前者给后者发指令我要干什么,CPU把他的指令变成现实
    * 二者必须很好的匹配计算机才能很好的工作
  • Linux内核中与文件Cache操作相关的API有很多,按其使用方式可以分成两类:一类是以拷贝方式操作的相关接口, 如read/write/sendfile等,其中sendfile在2.6系列的内核中已经不再支持;另一类是以地址映射方式操作的相关接口,如mmap等。
    * 第一种类型的API在不同文件的Cache之间或者Cache与应用程序所提供的用户空间buffer之间拷贝数据,其实现原理如图7所示。
    * 第二种类型的API将Cache项映射到用户空间,使得应用程序可以像使用内存指针一样访问文件,Memory map访问Cache的方式在内核中是采用请求页面机制实现的,首先,应用程序调用mmap(),陷入到内核中后调用do_mmap_pgoff。该函数从应用程序的地址空间中分配一段区域作为映射的内存地址,并使用一个VMA(vm_area_struct)结构代表该区域,之后就返回到应用程。当应用程序访问mmap所返回的地址指针时(图中4),由于虚实映射尚未建立,会触发缺页中断。之后系统会调用缺页中断处理函数,在缺页中断处理函数中,内核通过相应区域的VMA结构判断出该区域属于文件映射,于是调用具体文件系统的接口读入相应的Page Cache项,并填写相应的虚实映射表。经过这些步骤之后,应用程序就可以正常访问相应的内存区域了。

mumap()

//接触文件或设备对内存的映射,成功返回0,失败返回-1设errno
int munmap(void *addr, size_t length);

shm_unlink()

//关闭进程打开的共享内存对象,成功返回0,失败返回-1
//Link with -lrt.
int shm_unlink(const char *name);

转载于:https://www.cnblogs.com/xiaojiang1025/p/5937323.html

Linux IPC POSIX 共享内存相关推荐

  1. linux ipc shmget 例子,Linux IPC之共享内存C 事例(示例代码)

    简介 共享内存(shared memory)是最简单的Linux进程间通信方式之一.使用共享内存,不同进程可以对同一块内存进行读写.由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不需要进行 ...

  2. Linux IPC实践(10) --Posix共享内存

    1. 创建/获取一个共享内存 #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #inc ...

  3. 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap

    IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...

  4. Linux四种共享内存技术(附源码):SystemV、POSIX mmap、memfd_create、dma-buf

    <Linux 下的进程间通信:管道.消息队列.共享文件.共享内存> <[共享内存]基于共享内存的无锁消息队列设计> <File Sealing & memfd_c ...

  5. Linux进程间通信:共享内存mmap、xsi和posix

    前言 本文主要说明在Linux环境上如何使用共享内存.阅读本文可以帮你解决以下问题: 什么是共享内存和为什么要有共享内存? 如何使用mmap进行共享内存? 如何使用XSI共享内存? 如何使用POSIX ...

  6. linux进程间通信:POSIX 共享内存

    文章目录 思维导图 通信原理 优势 POSIX 共享内存 编程接口 编程案例 思维导图 之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存 POS ...

  7. linux进程间通信之Posix共享内存用法详解及代码举例

    Posix共享内存有两种非亲缘进程间的共享内存方法: 1).  使用内存映射文件,由open函数打开,再由mmap函数把返回的文件描述符映射到当前进程空间中的一个文件. 2). 使用共享内存区对象,由 ...

  8. Linux进程间通信六 Posix 共享内存简介与示例

    1. 共享内存简介 共享内存主要用于不同进程之间相互通信,因为操作的是同一块地址,不需要内核和用户层之间数据拷贝,属于最快的进程间通信方式,不过,为了防止读写冲突,一般需要额外的同步手段.之前介绍了S ...

  9. [转]Linux 进程间通信:共享内存

    (上) 级别: 初级 郑彦兴 (mlinux@163.com), 国防科大攻读博士学位 2003 年 5 月 01 日 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B ...

最新文章

  1. 用Quartus II Timequest Timing Analyzer进行时序分析 :实例讲解 (一)
  2. GoldenGate复制单表开并行
  3. ECJTUACM16 Winter vacation training #5 题解源码
  4. Route Flap Dampening
  5. ADO.NET开发总结(学习笔记)
  6. EnableAutoConfiguration自动配置底层原理
  7. 让阿里京东疯狂掐架的方兴东,究竟是何方神圣?
  8. fpga从入门到放弃(一)基于vivado2018环境开发板Artix 7系列BASYS3(更新中)
  9. docker镜像删除
  10. 蚂蚁金服 Java RPC 开源框架—SOFARPC
  11. 动物统计加强版 nyoj290
  12. ubuntu 下安装 qq wechat VirtualBox notepadqq
  13. 用Python求解拿鸡蛋问题
  14. 【k.11】python+appium+雷电模拟器 app自动化测试 demo 教学
  15. 反锯齿渲染技术--SMAA
  16. 运动无线蓝牙耳机哪款好、运动无线蓝牙耳机推荐
  17. sse服务器推送性能,SSE 服务端向客户端推送
  18. 从黄金时代到没落尽头,“寻求出售”的GoPro遭遇了什么?
  19. python将excel导入mysql_【Python】将excel文件导入mysql数据库
  20. PowerBI/DAX的计算组功能是什么?怎么用?

热门文章

  1. 创建二叉树的代码_解二叉树的右视图的两种方式
  2. python理论知识选择题_python基础知识练习题(二)
  3. c oracle更新参数化,Dapper的参数化更新和插入?
  4. 离散数学计算机科学丛书答案,计算机《离散数学》期中试卷答案.docx
  5. mysql fulsh_mysql之备份和恢复(msyqldump、LVM、xtrabackup)
  6. fragment photoshop_史上最接地气的Photoshop?谈PS 2021的黑科技 - Adobe
  7. jupyter python版本_Jupyter使用了错误的python版本
  8. android 获取已安装应用的安装包,Android获取设备已安装的应用
  9. mysql procedure
  10. javacript 字典