mmap

目录

  • Memory-mapped I/O
    • mmap
    • mprotect
    • msync
    • munmap


说明:内容来自APUE第2版中文版和相关函数的man手册。


Memory-mapped I/O

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

mmap

       为了使用这一功能,应首先告诉内核将一个文件映射到一个存储区域中。这一任务由mmap函数实现,其函数原型与所在头文件如下:

#include 
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset);
// 成功,返回映射区域的起始地址;失败,返回MAP_FAILED[(void *) -1],并设置errno。

       mmap在虚拟地址空间中创建一个映射。
       函数mmap() 与函数 mmap64() 的区别在最后一个参数,可以使应用程序访问更大的文件。
       每个参数及含义如下:

参数 描述
addr 映射存储区的起始地址。
length 存储区长度,单位:字节。
prot 对映射存储区的保护要求。
flags 确定映射的更新对映射相同区域的其他进程是否可见,以及是否对文件执行更新。
fd 要映射文件的文件描述符。
offset 要映射字节在文件中的起始偏移量。

       相关参数的详细信息:
       addr: 通常设置为0。

addr 描述
0(NULL) 由内核选择该映射区的起始地址。
非空 若未设置MAP_FIXED,内核将此视作在何处开辟映射区的一个建议,并不一定使用它,Linux将在页边界附近创建映射。
若设置了MAP_FIXED,则在指定的位置开辟映射区。

       prot: 指定映射存储区的保护要求不能超过文件open模式访问权限,若文件是使用O_RDONLY打开的,那么对映射存储区就不能指定PROT_WRITE,否则,对映射区执行写操作时,将产生SIGSEGV信号,发生Segment Fault。prot的取值如下表,可取任意一个或任意组合的按位或。

prot 描述
PROT_EXEC 映射区可执行。
PROT_READ 映射区可读。
PROT_WRITE 映射区可写。
PROT_NONE 映射区不可访问。

       flags: 其值通常为MAP_SHARED。其他常用值如下表:

flags 描述
MAP_SHARED 共享存储区。存储操作将修改映射文件,即此映射区的存储操作相当于对该文件的写操作。
调用msync() 或 munmap()之前,文件可能并未被更新。
MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本。(Create a private copy-on-write mapping.)
所有后来对该映射区的引用都是引用该副本,而不是原始文件。
MAP_FIXED 返回值必须等于addr,即在指定的addr处开辟映射区。移植性差,不鼓励使用此标志。

       还有其他的一些标志,详见mmap手册。

MAP_SHARED和MAP_PRIVATE是POSIX所要求的。在遵循POSIX的系统中,对MAP_FIXED的支持是可选的,遵循XSI的系统则要求支持此标志。

       addr 和 offset通常应该是系统虚拟页长度的倍数。虚拟页长可使用带参数 _SC_PAGESIZE 或 _SC_PAGE_SIZE 的 sysconf 函数获取。addr 和 offset 通常设置为0,所以这种要求一般并不重要。


mprotect

       创建映射存储区后,其保护权限可以通过 mprotect() 函数来更改。其原型如下:

int mprotect(const void *addr, size_t len, int prot);
// 成功,返回0;失败,返回-1,并设置errno。

       参数及意义同函数 mmap() 。


msync

       此函数可以将映射存储区中被修改的内容冲洗到被映射的文件中。其原型如下:

int msync(void *addr, size_t length, int flags);
// 成功,返回0;失败,返回-1,并设置errno。

       如果映射是私有的,那么不修改被映射的文件。
       flags参数使我们对如何冲洗存储区有某种程度的控制。其可用取值如下:

flags 描述
MS_ASYNC 设定了更新计划,函数调用立即返回。简化被写页的调度。
MS_SYNC 在此函数返回前等待写操作完成。
MS_INVALIDATE 可选项。要求使同一文件的其他映射无效。

       可以使用按位或的方式使用这些值,但不能同时指定 MS_ASYNC 与 MS_SYNC 。


munmap

       要解除映射,一是终止进程,二是调用 munmap() 函数,关闭文件描述符并不解除映射区。munmap() 函数的原型如下:

int munmap(void *addr, size_t length);
// 成功,返回0;失败,返回-1,并设置errno。

       相关示例可以查看mmap的手册。


       将一个普通文件复制到另一个普通文件中时,存储映射I/O比较快。但是有一些限制,例如,不能用其在某些设备(如网络设备或终端设备)之间进行复制,并且在对被复制的文件进行映射后,也要注意该文件的长度是否改变。尽管如此,某些应用程序会从存储映射I/O得到好处,因为它处理的是存储空间而不是读、写一个文件,所以常常可以简化算法。从存储映射I/O中得益的一个例子是对帧缓冲区设备的操作,该设备引用一个位图式显示(bitmapped display)。

你可能感兴趣的:(C)