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

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录

(一)IPC共享内存和文件映射的区别 1

(二)共享内存实现流程总结 1

(三)存储映射I/O(包含实现原理说明) 2

文件映射API补充 4

(四)IPC共享存储(包含实现原理说明) 6

(五)共享内存实现基本原理10

(六)IPC共享内存实现机制11

(七)文件映射的实现机制13

(一)IPC共享内存和文件映射的区别

1. 文件映射的页框是磁盘文件高速缓存中的页框,内核线程pdflush会将页框中的内容回写进磁盘,如果是私有映射类型,将会进行写时复制。而IPC共享内存映射的是一种特殊文件系统中的文件高速缓存,它没有相应的磁盘映像。

2. IPC共享内存只存在于内存中,系统重新启动,数据将会丢失。而文件共享映射会将数据写回磁盘。

3. IPC共享内存的大小是在创建的时候指定,而且大小不能改变,而文件在创建时大小为0,此时还不能建立映射,文件的大小会间接的决定映射区的大小。例如文件的大小是123,而要求映射的区域大小是4096*2,但实际只会分配4096的映射空间,此时引用4096以后的线性空间将引起缺页异常。

4. 当第一次读取共享内存时IPC共享内存对象将分配一个新的页框,而文件映射分配新页框的同时会将磁盘中的数据写入新页框。

5. IPC共享内存不需要写回磁盘操作,完全是为共享内存而设计,所以使用效率会更高。

6. IPC共享内存对象必须调用shmctl()显示的撤销,否则会一直保留着,使用key或者id号定位一个共享内存对象,key和id号的对应关系并不是固定的。例如,第一次使用key建立一个共享内存对象为shm1对应的id为id1,之后系统重新启动,然后再使用key 建立一个共享内存对象shm2,对应的id是id2,此时id2和id1是不同的。而文件映射使用相同的路径将会定位相同的磁盘文件。

总结:IPC共享内存和文件映射的实现机制是一样的,文件映射的目的是加快对文件的读写速度,而IPC共享内存就是为了共享内存而设计的,所以效率会高一些。

(二)共享内存实现流程总结

1. 建立一个线性区对象struct vm_area_struct 并加入进程的内存描述符current->mm中。

函数mmap()和shmat()就是用于建立并注册线性区对象,这个对象中的struct file *vm_file指向映射文件的文件对象,vm_page_prot是线性区中页框的访问许可权。但此时并未修改进程的页表,而是注册相应的缺页异常回调函数,注册在对象的vm_ops。

2. 当进程第一次访问共享内存区时,由于相应的页表还未填写,将产生缺页异常,并根据线性地址找到对应的线性区对象,然后调用前边注册过的缺页异常回调函数,并根据vm_file文件对象和vm_page_prot的信息来填写相应的页表项,最后重新执行产生缺页异常的代码。

说明:文件映射和IPC共享内存映射的物理页框都是磁盘文件的页高速缓存中的,IPC 共享内存使用一种特殊文件系统,这个文件系统并没有对应的磁盘映像,只是复用了文件系统的框架。更详细的内容参见后边的五,六,七节。

下面3,4节是《UNIX环境高级编程》对文件映射和IPC共享内存的讲解,已经说明的很详细了,我在它的基础上附加了一些内核实现原理的说明,实现原理说明部分放在括号内。

(三)存储映射I/O(包含实现原理说明)

存储映射I/O使一个磁盘文件与存储空间中的一个缓存相映射。于是当从缓存中取数据,就相当于读文件中的相应字节。与其类似,将数据存入缓存,则相应字节就自动地写入文件。这样,就可以在不使用read和write的情况下执行I/O。

为了使用这种功能,应首先告诉内核将一个给定的文件映射到一个存储区域中。这是由mmap函数实现的。

#include

#include

void * mmap(void addr, size_t len, int prot, int flag, int fd, off_t off) ;

返回:若成功则为映射区的起始地址,若出错则为- 1

addr参数用于指定映射存储区的起始地址。通常将其设置为0,这表示由系统选择该映射区的起始地址。此函数的返回地址是:该映射区的起始地址。fd指定要被映射文件的描述符(fd用于定位是哪个磁盘文件的页高速缓存)。在映射该文件到一个地址空间之前,先要打开该文件。len是映射的字节数。off是要映射字节在文件中的起始位移量(下面将说明对off值有某些限制)。

在说明其余参数之前,先看一下存储映射文件的基本情况。图12 - 12显示了一个存储映射文件。

在此图中,“起始地址”是mmap的返回值。在图中,映射存储区位于堆和栈之间:这属于实现

细节,各种实现之间可能不同。

prot参数说明映射存储区的保护要求。见表12 - 8。

对于映射存储区所指定的保护要求与文件的open方法匹配。例如,若该文件是只读打开的,那么对映射存储区就不能指定PROT _WRITE。(对存储映射区的保护是通过设置页表项的保护标志来实现的,如果页表项的read/write标志位为0,说明页是只读的,如果进程试图修改页的内容,将产生段错误,这些保护方案都是由CPU硬件控制的)flag参数影响映射存储区的多种属性:

? MAP_FIXED 返回值必须等于addr。因为这不利于可移植性,所以不鼓励使用此标志。如果未指定此标志,而且addr非0,则内核只把addr视为何处设置映射区的一种建议。通过将addr指定为0可获得最大可移植性。

? MAP_SHARED 这一标志说明了本进程对映射区所进行的存储操作的配置。此标志指定存储操作修改映射文件—也就是,存储操作相当于对该文件write。(这里映射的页是包含在文件的页高速缓存中,用户态进程在读写磁盘的时候,内核先在页高速缓存中增加一个新页,将所请求的磁盘块写入新页,用户态进程从页高速缓存中取出数据。如果要写入数据,也是要添加一个页将磁盘中的数据写入该页,然后再将数据写入该页,内核会在一定的时机对磁盘进行更新。)

(以上的页高速缓存是组织在inode的i_mmaping对象中,对于一个磁盘文件唯一对应一个磁盘inode,每个磁盘inode也唯一对应一个内核inode,也就是,每个磁盘文件只有一个页高速缓存,如果两个进程映射的是同一个文件的页高数缓存,则它们共享相同的物理页)

? MAP_PRIVATE 本标志说明,对映射区的存储操作导致创建该映射文件的一个副本。所有后来对该映射区的存访都是存访该副本,而不是原始文件。(这里内核用到了写时复制技术,在相应的页表项中设置写时复制标志,当进程试图修改该页,内核将会产生缺页异常,内核就把该页框进行复制,并在进程页表中用复制的页来替换原来的页框,显然这个新的页框已经不在页高速缓存中了,对页框的内容进行修改将不会写回文件,其它进程将无法共享这个页框。如果本进程还未进行写复制,而其它进程修改了页的内容,本进程是可以获得更新后的数据)

因为映射文件的起动位移量受系统虚存页长度的限制,那么如果映射区的长度不是页长度的整数倍时,将如何呢?假定文件长12字节,系统页长为512字节,则系统通常提供512字节的映射区,其中后500字节被设0。可以修改这50字节,但任何变动都不会在文件中反映出来。(这是由于内核分配线性区和分配物理内存都是以页为单位)与映射存储区相关有两个信号: SIGSEGV和SIGBUS。信号SIGSEGV通常用于指示进程试图存取它不能存取的存储区。如果进程企图存数据到用mmap指定为只读的映射存储区,那么也产生此信号。如果存取映射区的某个部分,而在存取时这一部分已不存在,则产生

相关文档
最新文档