您的位置首页>企业动态>

Linux IPC POSIX 共享内存

导读 大家好,我是极客范的本期栏目编辑小友,现在为大家讲解Linux IPC POSIX 共享内存问题。模型 include istd h for stat()

大家好,我是极客范的本期栏目编辑小友,现在为大家讲解Linux IPC POSIX 共享内存问题。

模型# include istd . h//for stat()# include sys/types . h//for stat()# include sys/mman . h # include sys/stat . h # include stentl . hshm _ open()//create/Get共享内存fd ftruncate() //creator调整文件大小mmap() //将fd映射到内存munmap()//demaps FD shm _ unlink()//删除共享内存shm_open//创建/获取共享内存的文件描述符,并成功返回文件描述符。-1//与-lrt链接。int SHM _ open (constchar * name,int oflag,mode _ tmode)失败;输出模式

访问模式:O_RDONLY以只读方式打开共享内存对象O_RDWR以读写方式打开共享内存对象打开时间标志(按位或): o _ creat表示创建共享内存对象。新创建的对象将被初始化为0字节,可以使用ftuncate()调整其大小。O _ EXCL用于确保成功创建共享内存对象。如果对象已经存在,它将返回一个错误。O_TRUNC意味着如果共享内存对象已经存在,它将被清空。模式:(如0664等)

run cate()//调整fd指向的文件大小,成功返回0,但未能返回-1。set errno//vs truncate()int ftruncate(int FD,off _ tle length);如果指定了原始文件大小,原始文件的冗余部分将被删除。

int res=ftruncate(fd,3 * sizeof(Emp));//使用sizeof,并且emp(类型)不是Emp(对象)如果(-1==RES) perror ('ftruncate '),则退出(-1);fstat()//获取文件状态,成功返回0,失败返回-1。设置errno//vsstat()int lstat(const char * pathname,struct stat * buf);int fstat(int fd,struct stat * buf);buf:stat类型的指针。

struct stat { dev _ t st _ devino _ t _ ST _ ino的设备的ID;mode _ t ST _ mode;八进制u使用了int o% n link _ t ST _ n link _ n link;uid _ t ST _ uid;GID _ t ST _ GID;dev _ t ST _ rdev;off _ t ST _ size;ld% blk size _ t ST _ blk size;blkcnt _ t _ ST _ blocks;struct TImespec ST _ ATim;struct time spec ST _ mtim;LD%,第二个结构timespec st _ ctim};//eg:st_mode=100664 //100是文件类型//664是权限。通过100664和0777 bitwise and get ST _ mtime=1462787968//second mmap()//将文件或设备的虚拟内存空间映射到进程。映射成功后,对相应文件或设备的操作相当于。

部分的最小页面数决定传统文件访问//要求对文件进行可读可写的的打开!!!//成功返回映射区的指针,失败返回-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_EXECUTABLEignoredMAP_FILE用来保持兼容性,ignoredMAP_FIXED不要对addr参数进行处理确确实实的放在addr指向的地址,此时addr一定时页大小的整数倍,MAP_GROWSDOWN用在栈中,告诉VMM映射区应该向低地址扩展MAP_HUGETLB (since Linux 2.6.32)用于分配"大页"

fd: file decriptoroffset: 文件中的偏移量

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跳到内存地址BOS是软件的核心,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设errnoint munmap(void *addr, size_t length);shm_unlink()

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

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。