存储映射I/O能将一个磁盘文件映射到存储空间中的一个缓冲区上,于是可以用对缓冲区的读写代替对磁盘文件的读写,这样就可以在不使用read和write的情况下执行I/O。为了实现这种功能,应首先将一个给定的文件映射到一个存储区域中,这由mmap函数实现。
注:子进程能够通过fork继承父进程的存储映射区。
mmap函数
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int fd, off_t off);
返回值:若成功,返回映射区的起始地址; 若出错,返回MAP_FAILED
参数
addr
用于指定映射存储区的起始地址。通常将其设置为0,表示由系统选择该起始地址,并由函数返回。
fd
指定要被映射文件的描述符。在文件映射到地址空间之前,必须先打开该文件。len
指定要映射的字节数。off
要映射字节在文件中的起始偏移量。prot
指定映射存储区域的保护要求。如下图所示prot 说明 PROT_READ 映射区可读 PROT_WRITE 映射区可写 PROT_EXEC 映射区可执行 PROT_NONE 映射区不可访问 可将proc参数指定为PROT_NONE,也可以指定为其他三项的任意组合的按位或。要注意,对于指定映射区域的保护要求不能超过文件open模式访问权限。例如,文件是只读打开的,就不能对映射区指定PROT_WRITE。
flag
下图展示了一个存储映射文件
图中“起始地址”是mmap的返回值,映射存储区位于堆和栈之间(具体取决于实现)
下面是flag参数可选的值,它们影响着映射存储区的多种属性:
每种实现可能还有其它的一些标志值,具体参见系统手册。MAP_FIXED
返回值必须等于参数addr。这不利于可移植性,所以不推荐使用。如未指定此标志,且addr不为0,则系统只把addr作为一个建议,但是不保证会使用该地址。MAP_SHARED
这一标志描述了进程对映射区所进行的存储操作的配置。该标志指定存储操作修改映射文件,也就是存储操作相当于对该文件的write。
注意:必须指定本标志或下一个标志(MAP_PRIVATE),但不能同时指定。MAP_PRIVATE
本标志说明,对映射区的存储操作导致该映射文件的一个私有副本。所有后来对该映射区的引用都是引用该副本。任何修改只影响该副本,而不影响源文件。
off和addr通常被要求是虚拟存储页长的整数倍,该长度可通过使用参数_SC_PAGE_SIZE的sysconf函数获得。
相关信号
- SIGSEGV
只是进程试图访问对它不可用的存储区。如果映射区指定为只读,那么试图向其中写入数据就会产生该信号 SIGBUS
如果映射区的某部分在访问时已不存在,则产生该信号。
munmap函数
当进程终止时,会自动解除存储映射区的映射,或者调用munmap函数也可以解除映射区。关闭被映射的文件描述符并不能解除映射区。munmap并不会使映射区的内容写入到磁盘文件中,对于MAP_SHARED区的数据,会由内核在某个时刻将其写入磁盘文件;而对于MAP_PRIVATE区的修改会被丢弃。
#include <sys/mman.h>
int munmap(void *addr, size_t len)
//返回值:成功,返回0;出错,返回-1
;
mprotect函数
调用该函数可以修改一个现有映射的权限。
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
//返回值:成功,返回0;出错,返回-1
msync函数
将被修改的页冲洗到被映射的文件中。
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
//返回值:成功,返回0;出错,返回-1