mmap()
系統呼叫在呼叫進程的虛擬地址空間中提供對映,將檔案或裝置對映到記憶體中。 下面是兩種型別 -
檔案對映或檔案支援的對映 - 此對映將進程的虛擬記憶體區域對映到檔案。 這意味著讀取或寫入這些記憶體區域會導致檔案被讀取或寫入。這是預設的對映型別。
匿名對映 - 此對映對映進程的虛擬記憶體區域,不受任何檔案的支援。 內容被初始化為零。 這種對映類似於動態記憶體分配(malloc()),在某些malloc()
實現中用於某些分配。
一個進程對映中的記憶體可以與其他進程中的對映共用。 這可以通過兩種方式完成 -
當兩個或多個進程共用相同的頁面時,每個進程可以根據對映型別檢視其他進程所做的頁面內容更改。 對映型別可以是私有的也可以是共用的 -
#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個)。 欄位標誌指示對映型別或MAP_PRIVATE
或MAP_SHARED
。 欄位'fd'
表示標識要對映的檔案的檔案描述符,欄位'offset'
表示檔案的起始點,如果需要對映整個檔案,offset
應該是零。
#include <sys/mman.h>
int munmap(void *addr, size_t length);
上述系統呼叫在成功時返回0
,錯誤時返回-1
。
系統呼叫munmap
,執行已對映記憶體區域的對映。 欄位addr
指示對映的起始地址,length
指示要被對映的對映的大小(以位元組為單位)。 通常,對映和解對映將針對整個對映區域。 如果這必須有所不同,那麼它應該被縮小或分成兩部分。 如果addr
沒有任何對映,這個呼叫將不起作用,呼叫返回0
(成功)。
讓我們考慮一個例子 -
第1步 - 寫入檔案如下所示的字母數位字元 -
0 | 1 | 2 | … | 25 | 26 | 27 | 38 | … | 59 | 60 | 61 |
---|---|---|---|---|---|---|---|---|---|---|---|
A | B | C | … | Z | 0 | 1 | 2 | … | 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