Linux共享内存实例及文件映射编程及实现原理

上传人:hs****ma 文档编号:500689682 上传时间:2023-03-02 格式:DOC 页数:11 大小:54KB
返回 下载 相关 举报
Linux共享内存实例及文件映射编程及实现原理_第1页
第1页 / 共11页
Linux共享内存实例及文件映射编程及实现原理_第2页
第2页 / 共11页
Linux共享内存实例及文件映射编程及实现原理_第3页
第3页 / 共11页
Linux共享内存实例及文件映射编程及实现原理_第4页
第4页 / 共11页
Linux共享内存实例及文件映射编程及实现原理_第5页
第5页 / 共11页
点击查看更多>>
资源描述

《Linux共享内存实例及文件映射编程及实现原理》由会员分享,可在线阅读,更多相关《Linux共享内存实例及文件映射编程及实现原理(11页珍藏版)》请在金锄头文库上搜索。

1、Linux共享内存实例及文件映射编程及实现原理.txt如果我能够看到自己的影子,我想它一定很忧伤,因为我把快乐都留在了前面。容易伤害别人和自己的人,总是对距离的边缘模糊不清的人。目录(一)IPC共享内存和文件映射的区别1(二)共享内存实现流程总结1(三)存储映射I/O(包含实现原理说明)2文件映射API补充4(四)IPC共享存储(包含实现原理说明)6(五)共享内存实现基本原理10(六)IPC共享内存实现机制11(七)文件映射的实现机制13(一)IPC共享内存和文件映射的区别1. 文件映射的页框是磁盘文件高速缓存中的页框,内核线程pdflush会将页框中的内容回写进磁盘, 如果是私有映射类型,将

2、会进行写时复制。而IPC共享内存映射的是一种特殊文件系统中的文件高速缓存,它没有相应的磁盘映像。2. IPC共享内存只存在于内存中,系统重新启动,数据将会丢失。而文件共享映射会将数据写回磁盘。3. IPC共享内存的大小是在创建的时候指定,而且大小不能改变,而文件在创建时大小为0,此时还不能建立映射,文件的大小会间接的决定映射区的大小。例如文件的大小是123,而要求映射的区域大小是4096*2,但实际只会分配4096的映射空间,此时引用4096以后的线性空间将引起缺页异常。4. 当第一次读取共享内存时IPC共享内存对象将分配一个新的页框,而文件映射分配新页框的同时会将磁盘中的数据写入新页框。5.

3、 IPC共享内存不需要写回磁盘操作,完全是为共享内存而设计,所以使用效率会更高。6. IPC共享内存对象必须调用shmctl()显示的撤销,否则会一直保留着,使用key或者id号定位一个共享内存对象,key和id号的对应关系并不是固定的。例如,第一次使用key建立一个共享内存对象为shm1对应的id为id1,之后系统重新启动,然后再使用key建立一个共享内存对象shm2,对应的id是id2,此时id2和id1是不同的。而文件映射使用相同的路径将会定位相同的磁盘文件。总结:IPC共享内存和文件映射的实现机制是一样的,文件映射的目的是加快对文件的读写速度,而IPC共享内存就是为了共享内存而设计的,

4、所以效率会高一些。(二)共享内存实现流程总结1. 建立一个线性区对象struct vm_area_struct 并加入进程的内存描述符current-mm中。函数mmap()和shmat()就是用于建立并注册线性区对象,这个对象中的struct file *vm_file指向映射文件的文件对象,vm_page_prot是线性区中页框的访问许可权。但此时并未修改进程的页表,而是注册相应的缺页异常回调函数,注册在对象的vm_ops。2. 当进程第一次访问共享内存区时,由于相应的页表还未填写,将产生缺页异常,并根据线性地址找到对应的线性区对象,然后调用前边注册过的缺页异常回调函数,并根据vm_fil

5、e文件对象和vm_page_prot的信息来填写相应的页表项,最后重新执行产生缺页异常的代码。说明:文件映射和IPC共享内存映射的物理页框都是磁盘文件的页高速缓存中的,IPC共享内存使用一种特殊文件系统,这个文件系统并没有对应的磁盘映像,只是复用了文件系统的框架。更详细的内容参见后边的五,六,七节。下面3,4节是UNIX环境高级编程对文件映射和IPC共享内存的讲解,已经说明的很详细了,我在它的基础上附加了一些内核实现原理的说明,实现原理说明部分放在括号内。(三)存储映射I/O(包含实现原理说明)存储映射I/O使一个磁盘文件与存储空间中的一个缓存相映射。于是当从缓存中取数据,就相当于读文件中的相

6、应字节。与其类似,将数据存入缓存,则相应字节就自动地写入文件。这样,就可以在不使用read和write的情况下执行I/O。为了使用这种功能,应首先告诉内核将一个给定的文件映射到一个存储区域中。这是由mmap函数实现的。#include #include void * mmap(void addr, size_t len, int prot, int flag, int fd, off_t off) ;返回:若成功则为映射区的起始地址,若出错则为- 1addr参数用于指定映射存储区的起始地址。通常将其设置为0,这表示由系统选择该映射区的起始地址。此函数的返回地址是:该映射区的起始地址。fd指定要

7、被映射文件的描述符(fd用于定位是哪个磁盘文件的页高速缓存)。在映射该文件到一个地址空间之前,先要打开该文件。len是映射的字节数。off是要映射字节在文件中的起始位移量(下面将说明对off值有某些限制)。在说明其余参数之前,先看一下存储映射文件的基本情况。图12 - 12显示了一个存储映射文件。在此图中,“起始地址”是mmap的返回值。在图中,映射存储区位于堆和栈之间:这属于实现细节,各种实现之间可能不同。prot参数说明映射存储区的保护要求。见表12 - 8。对于映射存储区所指定的保护要求与文件的open方法匹配。例如,若该文件是只读打开的,那么对映射存储区就不能指定PROT _WRITE

8、。(对存储映射区的保护是通过设置页表项的保护标志来实现的,如果页表项的read/write标志位为0,说明页是只读的,如果进程试图修改页的内容,将产生段错误,这些保护方案都是由CPU硬件控制的)flag参数影响映射存储区的多种属性:? MAP_FIXED 返回值必须等于addr。因为这不利于可移植性,所以不鼓励使用此标志。如果未指定此标志,而且addr非0,则内核只把addr视为何处设置映射区的一种建议。通过将addr指定为0可获得最大可移植性。? MAP_SHARED 这一标志说明了本进程对映射区所进行的存储操作的配置。此标志指定存储操作修改映射文件也就是,存储操作相当于对该文件write。

9、(这里映射的页是包含在文件的页高速缓存中,用户态进程在读写磁盘的时候,内核先在页高速缓存中增加一个新页,将所请求的磁盘块写入新页,用户态进程从页高速缓存中取出数据。如果要写入数据,也是要添加一个页将磁盘中的数据写入该页,然后再将数据写入该页,内核会在一定的时机对磁盘进行更新。)(以上的页高速缓存是组织在inode的i_mmaping对象中,对于一个磁盘文件唯一对应一个磁盘inode,每个磁盘inode也唯一对应一个内核inode,也就是,每个磁盘文件只有一个页高速缓存,如果两个进程映射的是同一个文件的页高数缓存,则它们共享相同的物理页)? MAP_PRIVATE 本标志说明,对映射区的存储操作

10、导致创建该映射文件的一个副本。所有后来对该映射区的存访都是存访该副本,而不是原始文件。(这里内核用到了写时复制技术,在相应的页表项中设置写时复制标志,当进程试图修改该页,内核将会产生缺页异常,内核就把该页框进行复制,并在进程页表中用复制的页来替换原来的页框,显然这个新的页框已经不在页高速缓存中了,对页框的内容进行修改将不会写回文件,其它进程将无法共享这个页框。如果本进程还未进行写复制,而其它进程修改了页的内容,本进程是可以获得更新后的数据)因为映射文件的起动位移量受系统虚存页长度的限制,那么如果映射区的长度不是页长度的整数倍时,将如何呢?假定文件长12字节,系统页长为512字节,则系统通常提供

11、512字节的映射区,其中后500字节被设0。可以修改这50字节,但任何变动都不会在文件中反映出来。(这是由于内核分配线性区和分配物理内存都是以页为单位)与映射存储区相关有两个信号: SIGSEGV和SIGBUS。信号SIGSEGV通常用于指示进程试图存取它不能存取的存储区。如果进程企图存数据到用mmap指定为只读的映射存储区,那么也产生此信号。如果存取映射区的某个部分,而在存取时这一部分已不存在,则产生SIGBUS信号。例如,用文件长度映射一个文件,但在存访该映射区之前,另一个进程已将该文件截短。此时,如果进程企图存取对应于该文件尾端部分的映射区,则接收到SIGBUS信号。(对信号的实现机制有

12、待进一步分析)在fork之后,子进程继承存储映射区(因为子进程复制父进程地址空间,而存储映射区是该地址空间中的一部分),但是由于同样的理由,exec后的新程序则不继承此存储映射区。(关闭文件描述符也不影响存储映射区,磁盘文件的页高速缓存并不会因为进程的撤销而撤销,如果有足够的空闲内存,页高速缓存中的页将长期存在,使其它进程再使用该页时不再访问磁盘。)进程终止时,或调用了munmap之后,存储映射区就被自动去除。关闭文件描述符fd并不解除映射区。(关闭存储映射区,只是撤销进程页表中的相应目录项,并不影响页高速缓存。)#include #include int munmap(void addr,s

13、ize_t len) ;返回:若成功则为0,若出错则为- 1munmap 并不影响被映射的对象也就是说,调用munmap并不使映射区的内容写到磁盘文件上。对于MAP_SHARED区磁盘文件的更新,在写到存储映射区时按内核虚存算法自动进行。(pdflush内核线程用于刷新脏页)例子程序:#include #include #include #include #include #include int main(int argc, char *argv)int fd, i, counter;pid_t pid;char *area = NULL;if(fd = open(test, O_RDWR)

14、 )= 0)printf(open errorn);area = (char *)mmap(0, sizeof(long), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);printf(area:%pn, area);close(fd);*(area + 1) = c;文件映射API补充msync函数的使用原型:? #include ? int msync(const void *start, size_t length, int flags);msync函数用来把映像的文件写入磁盘。调用msync可以用对内存中的映像的更新写入一个被映像的文件,被强行写

15、入到磁盘的内存取从start指定的地址开始,写入length个字节的数据。flags可以是下面的一个值或多个的逻辑“或”:? 1、MS_ASYNC 调度一次写入操作然后返回? 2、MS_SYNC 在msync返回前写入数据? 3、MS_INVALIDATE 让映像到同一文件的映像无效,以便用新数据更新它们(MS_INVALIDATE的作用是使映射的页高速缓存中的内容无效,重新从磁盘写入数据到映射的页高速缓存。可以使用MS_INVALIDATE来测试内核是否进行页高速缓存数据的回写磁盘操作,测试过程:写一个字符到映射区,然后使用MS_INVALIDATE使映射区的数据失效,并从磁盘写入数据,从测试结果看字符会被写入磁盘,也就是说内核几乎在对映射区进行写入操作的同时就进行了回写磁盘操作)mprotect函数的使用mprotect函数修改在内存映像上的保护模式。函数原型:? #include ? #include ? int mprotect

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 模板/表格 > 财务表格

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号