mmap()
系統(tǒng)調(diào)用在調(diào)用進(jìn)程的虛擬地址空間中提供映射,將文件或設(shè)備映射到內(nèi)存中。 下面是兩種類型 -
文件映射或文件支持的映射 - 此映射將進(jìn)程的虛擬內(nèi)存區(qū)域映射到文件。 這意味著讀取或?qū)懭脒@些內(nèi)存區(qū)域會(huì)導(dǎo)致文件被讀取或?qū)懭?。這是默認(rèn)的映射類型。
匿名映射 - 此映射映射進(jìn)程的虛擬內(nèi)存區(qū)域,不受任何文件的支持。 內(nèi)容被初始化為零。 這種映射類似于動(dòng)態(tài)內(nèi)存分配(malloc()),在某些malloc()
實(shí)現(xiàn)中用于某些分配。
一個(gè)進(jìn)程映射中的內(nèi)存可以與其他進(jìn)程中的映射共享。 這可以通過(guò)兩種方式完成 -
當(dāng)兩個(gè)或多個(gè)進(jìn)程共享相同的頁(yè)面時(shí),每個(gè)進(jìn)程可以根據(jù)映射類型查看其他進(jìn)程所做的頁(yè)面內(nèi)容更改。 映射類型可以是私有的也可以是共享的 -
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
上述系統(tǒng)調(diào)用返回成功映射的起始地址,或者返回MAP_FAILED
出錯(cuò)。
虛擬地址addr
可以是用戶指定的,也可以是內(nèi)核生成的(將addr
作為NULL
傳遞)。 指示的字段長(zhǎng)度需要以字節(jié)為單位的映射大小。 字段prot表示內(nèi)存保護(hù)值,例如PROT_NONE
,PROT_READ
,PROT_WRITE
,PROT_EXEC
分別表示不可訪問(wèn),讀取,寫(xiě)入或執(zhí)行的區(qū)域。 該值可以是單個(gè)(PROT_NONE),也可以是三個(gè)標(biāo)志中的任何一個(gè)(最后3個(gè))。 字段標(biāo)志指示映射類型或MAP_PRIVATE
或MAP_SHARED
。 字段'fd'
表示標(biāo)識(shí)要映射的文件的文件描述符,字段'offset'
表示文件的起始點(diǎn),如果需要映射整個(gè)文件,offset
應(yīng)該是零。
#include <sys/mman.h>
int munmap(void *addr, size_t length);
上述系統(tǒng)調(diào)用在成功時(shí)返回0
,錯(cuò)誤時(shí)返回-1
。
系統(tǒng)調(diào)用munmap
,執(zhí)行已映射內(nèi)存區(qū)域的映射。 字段addr
指示映射的起始地址,length
指示要被映射的映射的大小(以字節(jié)為單位)。 通常,映射和解映射將針對(duì)整個(gè)映射區(qū)域。 如果這必須有所不同,那么它應(yīng)該被縮小或分成兩部分。 如果addr
沒(méi)有任何映射,這個(gè)調(diào)用將不起作用,調(diào)用返回0
(成功)。
讓我們考慮一個(gè)例子 -
第1步 - 寫(xiě)入文件如下所示的字母數(shù)字字符 -
0 | 1 | 2 | … | 25 | 26 | 27 | 38 | … | 59 | 60 | 61 |
---|---|---|---|---|---|---|---|---|---|---|---|
A | B | C | … | Z | 0 | 1 | 2 | … | x | y | z |
第2步 - 使用mmap()
系統(tǒng)調(diào)用將文件內(nèi)容映射到內(nèi)存中。 這將映射到內(nèi)存后返回起始地址。
第3步 - 使用數(shù)組表示法訪問(wèn)文件內(nèi)容(也可以使用指針表示法訪問(wèn)),因?yàn)椴粫?huì)讀取昂貴的read()
系統(tǒng)調(diào)用。 使用內(nèi)存映射,避免在用戶空間,內(nèi)核空間緩沖區(qū)和緩沖區(qū)緩存之間進(jìn)行多次復(fù)制。
第4步 - 重復(fù)讀取文件內(nèi)容,直到用戶輸入“-1”
(表示訪問(wèn)結(jié)束)。
第5步 - 執(zhí)行清理活動(dòng),即取消映射映射的內(nèi)存區(qū)域(munmap()
),關(guān)閉文件并刪除文件。
/* 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;
}
執(zhí)行上面示例代碼,得到以下結(jié)果 -
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