あなたの質問に対する正確な回答が見つからなかったので、もう 1 つ追加することにしました:
<オール>この質問に答える Linus Torvalds のコメントを見つけましたhttp://www.realworldtech.com/forum/?threadid=113923&curpostid=114068
マップされたページはファイルシステム キャッシュの一部です。つまり、そのページに変更を加えたユーザー プロセスが停止した場合でも、そのページは引き続きカーネルによって管理され、そのファイルへのすべての同時アクセスはカーネルを介して行われます。プロセスはそのキャッシュから提供されます。一部の古い Linux カーネルでは異なっていました。それが、一部のカーネル ドキュメントがまだ msync
を強制するように指示している理由です。 .
編集:ありがとう、RobH がリンクを修正しました。
編集:
Linux 4.15 以降、コヒーレンスを保証できる新しいフラグ MAP_SYNC が導入されました。
<ブロック引用>このフラグを使用した共有ファイル マッピングは、一部のメモリがプロセスのアドレス空間に書き込み可能にマップされている間、システムがクラッシュまたは再起動された後でも、同じオフセットで同じファイルに表示されることを保証します。
参照:
http://man7.org/linux/man-pages/man2/mmap.2.html ページで MAP_SYNC を検索
https://lwn.net/Articles/731706/
少し怠惰にならないように、データが確実にディスクに書き込まれるかどうかという質問には、コードを書くことで答えることにしました。答えは書かれるということです。
以下は、mmap されたファイルにデータを書き込んだ後、突然自分自身を強制終了するプログラムです:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct {
char data[100];
uint16_t count;
} state_data;
const char *test_data = "test";
int main(int argc, const char *argv[]) {
int fd = open("test.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);
if (fd < 0) {
perror("Unable to open file 'test.mm'");
exit(1);
}
size_t data_length = sizeof(state_data);
if (ftruncate(fd, data_length) < 0) {
perror("Unable to truncate file 'test.mm'");
exit(1);
}
state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0);
if (MAP_FAILED == data) {
perror("Unable to mmap file 'test.mm'");
close(fd);
exit(1);
}
memset(data, 0, data_length);
for (data->count = 0; data->count < 5; ++data->count) {
data->data[data->count] = test_data[data->count];
}
kill(getpid(), 9);
}
次のプログラムは、前のプログラムが終了した後に結果のファイルを検証します:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
typedef struct {
char data[100];
uint16_t count;
} state_data;
const char *test_data = "test";
int main(int argc, const char *argv[]) {
int fd = open("test.mm", O_RDONLY);
if (fd < 0) {
perror("Unable to open file 'test.mm'");
exit(1);
}
size_t data_length = sizeof(state_data);
state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
if (MAP_FAILED == data) {
perror("Unable to mmap file 'test.mm'");
close(fd);
exit(1);
}
assert(5 == data->count);
unsigned index;
for (index = 0; index < 4; ++index) {
assert(test_data[index] == data->data[index]);
}
printf("Validated\n");
}
混乱を招くものを見つけました:
<ブロック引用>munmap はマップされたオブジェクトに影響を与えません。つまり、munmap を呼び出しても、マップされた領域の内容がディスク ファイルに書き込まれません。 . MAP_SHARED 領域のディスク ファイルの更新は、カーネルの仮想メモリ アルゴリズムによって、メモリ マップ領域に格納する際に自動的に行われます。
これは UNIX® 環境での高度なプログラミング からの抜粋です .
Linux マンページから:
<ブロック引用>MAP_SHARED このマッピングを、このオブジェクトをマップする他のすべてのプロセスと共有します。リージョンへの保存は、ファイルへの書き込みと同じです。 msync(2) または munmap(2) が呼び出されるまで、ファイルは実際には更新されない場合があります。
2つは矛盾しているようです。 APUE は間違っていますか?