Inter-process-communication-memory-mapping
メモリマッピング
mmap()システムコールは、ファイルまたはデバイスをメモリにマップする呼び出しプロセスの仮想アドレス空間でのマッピングを提供します。 これは2種類あります-
ファイルマッピングまたはファイルバックアップマッピング-このマッピングは、プロセスの仮想メモリの領域をファイルにマッピングします。 これは、メモリのこれらの領域に対して読み取りまたは書き込みを行うと、ファイルが読み取りまたは書き込みされることを意味します。 これがデフォルトのマッピングタイプです。
匿名マッピング-このマッピングは、ファイルにバッキングされずにプロセスの仮想メモリの領域をマッピングします。 内容はゼロに初期化されます。 このマッピングは、動的メモリ割り当て(malloc())に似ており、特定の割り当ての一部のmalloc()実装で使用されます。
1つのプロセスマッピングのメモリは、他のプロセスのマッピングと共有できます。 これは2つの方法で行うことができます-
- 2つのプロセスがファイルの同じ領域をマップすると、それらは物理メモリの同じページを共有します。
- 子プロセスが作成された場合、親のマッピングを継承し、これらのマッピングは親と同じ物理メモリのページを参照します。 子プロセスでデータが変更されると、子プロセス用に異なるページが作成されます。
2つ以上のプロセスが同じページを共有する場合、各プロセスは、マッピングタイプに応じて他のプロセスによって行われたページコンテンツの変更を確認できます。 マッピングの種類は、プライベートまたは共有のいずれかです-
プライベートマッピング(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つのフラグのいずれか(最後の3)とORすることもできます。 フィールドフラグは、マッピングタイプまたはMAP_PRIVATEまたはMAP_SHAREDを示します。 フィールド「fd」はマッピングするファイルを識別するファイル記述子を示し、フィールド「offset」はファイルの開始点を示します。ファイル全体をマッピングする必要がある場合、オフセットはゼロでなければなりません。
#include <sys/mman.h>
int munmap(void *addr, size_t length);
上記のシステムコールは、成功すると0を返し、エラー時には-1を返します。
システムコールmunmapは、すでにメモリマップされた領域のマッピング解除を実行します。 フィールドaddrはマッピングの開始アドレスを示し、長さはマッピング解除するマッピングのサイズをバイト単位で示します。 通常、マッピングとマッピング解除は、マッピングされた領域全体に対して行われます。 これを異なるものにする必要がある場合は、縮小するか、2つの部分にカットする必要があります。 addrにマッピングがない場合、この呼び出しは効果がなく、呼び出しは0(成功)を返します。
私たちは例を考えてみましょう-
- ステップ1 *-以下に示すように、ファイルの英数字に書き込みます-
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