mmap()系统调用在调用进程的虚拟地址空间中提供映射,该映射将文件或设备映射到内存中.这有两种类型 :
文件映射或文件支持的映射 : 此映射将进程的虚拟内存区域映射到文件.这意味着读取或写入这些内存区域会导致文件被读取或写入.这是默认的映射类型.
匿名映射 : 此映射映射进程的虚拟内存区域,而不受任何文件的支持.内容初始化为零.此映射类似于动态内存分配(malloc()),并在某些malloc()实现中用于某些分配.
一个进程映射中的内存可以与其他映射中的映射共享流程.这可以通过两种方式完成 :
当两个进程映射文件的同一区域时,它们共享相同的区域物理内存的页面.
如果创建子进程,它会继承父进程的映射,这些映射指的是与物理内存相同的物理内存页面.家长.在子进程中的任何数据更改后,将为子进程创建不同的页面.
当两个或多个进程共享相同的页面,每个进程可以根据映射类型查看其他进程所做的页面内容的更改.映射类型可以是私有或共享 :
私有映射(MAP_PRIVATE) : 对此映射内容的修改对其他进程不可见,并且映射不会传送到基础文件.
共享映射(MAP_SHARED) : 对此映射内容的修改对其他进程可见,映射将传递到基础文件.
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
上述系统调用在成功时返回映射的起始地址,或者在出错时返回MAP_FAILED.
虚拟地址addr,可以是用户指定的,也可以是内核生成的(将addr作为NULL传递).指示的字段长度需要以字节为单位的映射大小.字段prot表示存储器保护值,例如PROT_NONE,PROT_READ,PROT_WRITE,PROT_EXEC,分别用于可能无法访问,读取,写入或执行的区域.该值可以是单个(PROT_NONE),也可以与三个标志中的任何一个(最后3个)进行OR运算.字段标志指示映射类型或MAP_PRIVATE或MAP_SHARED.字段'fd'表示标识要映射的文件的文件描述符,字段'offset'表示文件的起始点,如果需要映射整个文件,则偏移量应为零.
#include< sys/mman.h> int munmap(void * addr,size_t length);
上述系统调用在成功时返回0或在出错时返回-1.
系统调用munmap,执行取消映射已经存储器映射的区域.字段addr表示映射的起始地址,长度表示要取消映射的映射的字节大小.通常,映射和取消映射将用于整个映射区域.如果必须有所不同,则应将其缩小或分成两部分.如果addr没有任何映射,则此调用无效,并且调用返回0(成功).
让我们考虑一个示例 :
第1步 : 写入文件Alpha数字字符如下所示 :
0 | 1 | 2 | ... | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ... | 59 | 60 | 61 |
A | B | C | ... | Z | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | b | c | ... | x | y | z |
第2步 : 使用mmap()系统调用将文件内容映射到内存中.这将在映射到内存后返回起始地址.
步骤3 : 使用数组表示法访问文件内容(也可以使用指针表示法访问),因为不会读取昂贵的read()系统调用.使用内存映射,避免在用户空间,内核空间缓冲区和缓冲区缓存之间进行多次复制.
步骤4 : 重复读取文件内容,直到用户输入"-1"(表示访问结束).
步骤5 : 执行清理活动,即取消映射内存区域(munmap()),关闭文件并删除文件.
/* Filename: mmap_test.c */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h> void write_mmap_sample_data(); int main() { struct stat mmapstat; char *data; int minbyteindex; int maxbyteindex; int offset; int fd; int unmapstatus; write_mmap_sample_data(); if (stat("MMAP_DATA.txt", &mmapstat) == -1) { perror("stat failure"); return 1; } if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) { perror("open failure"); return 1; } data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0); if (data == (caddr_t)(-1)) { perror("mmap failure"); return 1; } minbyteindex = 0; maxbyteindex = mmapstat.st_size - 1; do { printf("Enter -1 to quit or "); printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex); scanf("%d",&offset); if ( (offset >= 0) && (offset <= maxbyteindex) ) printf("Received char at %d is %c\n", offset, data[offset]); else if (offset != -1) printf("Received invalid index %d\n", offset); } while (offset != -1); unmapstatus = munmap(data, mmapstat.st_size); if (unmapstatus == -1) { perror("munmap failure"); return 1; } close(fd); system("rm -f MMAP_DATA.txt"); return 0; } void write_mmap_sample_data() { int fd; char ch; struct stat textfilestat; fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666); if (fd == -1) { perror("File open error "); return; } // Write A to Z ch = 'A'; while (ch <= 'Z') { write(fd, &ch, sizeof(ch)); ch++; } // Write 0 to 9 ch = '0'; while (ch <= '9') { write(fd, &ch, sizeof(ch)); ch++; } // Write a to z ch = 'a'; while (ch <= 'z') { write(fd, &ch, sizeof(ch)); ch++; } close(fd); return; }
Enter -1 to quit or enter a number between 0 and 61: 3 Received char at 3 is D Enter -1 to quit or enter a number between 0 and 61: 28 Received char at 28 is 2 Enter -1 to quit or enter a number between 0 and 61: 38 Received char at 38 is c Enter -1 to quit or enter a number between 0 and 61: 59 Received char at 59 is x Enter -1 to quit or enter a number between 0 and 61: 65 Received invalid index 65 Enter -1 to quit or enter a number between 0 and 61: -99 Received invalid index -99 Enter -1 to quit or enter a number between 0 and 61: -1