C 将文件映射到内存,并在文件末尾写入
我正在Linux中试验内存映射文件,我有一个问题,当从不同进程映射同一个文件并在文件末尾之外写入时,实际会发生什么 我用vim手工创建了一个文件,并在其中写入了2个字节:C 将文件映射到内存,并在文件末尾写入,c,linux,file-io,linux-kernel,memory-mapped-files,C,Linux,File Io,Linux Kernel,Memory Mapped Files,我正在Linux中试验内存映射文件,我有一个问题,当从不同进程映射同一个文件并在文件末尾之外写入时,实际会发生什么 我用vim手工创建了一个文件,并在其中写入了2个字节: $ cat test_mmap aa 然后我写了两个非常简单的程序 第一个程序映射文件并修改映射,而不使用msync和munmap writer.c: int main(void){ int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU); cha
$ cat test_mmap
aa
然后我写了两个非常简单的程序
第一个程序映射文件并修改映射,而不使用msync
和munmap
writer.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
mapped_region[0] = '0';
mapped_region[1] = '1';
mapped_region[2] = '2';
mapped_region[3] = '3';
mapped_region[4] = '4';
mapped_region[5] = '5';
}
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
printf("%c\n", mapped_region[0]);
printf("%c\n", mapped_region[1]);
printf("%c\n", mapped_region[2]);
printf("%c\n", mapped_region[3]);
printf("%c\n", mapped_region[4]);
printf("%c\n", mapped_region[5]);
}
第二个是读取映射
reader.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
mapped_region[0] = '0';
mapped_region[1] = '1';
mapped_region[2] = '2';
mapped_region[3] = '3';
mapped_region[4] = '4';
mapped_region[5] = '5';
}
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
printf("%c\n", mapped_region[0]);
printf("%c\n", mapped_region[1]);
printf("%c\n", mapped_region[2]);
printf("%c\n", mapped_region[3]);
printf("%c\n", mapped_region[4]);
printf("%c\n", mapped_region[5]);
}
所以我跑了
$ ./writer && ./reader && cat /tmp/test/test_mmap
0
1
2
3
4
5
012
这意味着任何写入文件末尾之外的数据都会在映射中保留一段时间(尽管它不会写入文件),如果另一个进程因此映射同一区域,则写入文件末尾之外的数据不会按照以下步骤中的规定归零:
文件以页面大小的倍数映射。对于不是
页面大小的倍数,则剩余内存在
已映射,并且对该区域的写入不会写入文件
运行带有perf-e重大故障的读卡器。/reader
显示
0 major-faults
这意味着不会从磁盘读取任何页面。同时查看/proc//smap
我发现页面被标记为脏的和私有的(即使映射是使用MAP\u SHARED
标志创建的):
如果我在一段时间后运行reader进程(需要等待多长时间?),我观察到
$ ./reader
0
1
2
问题:如果一个进程修改了文件末尾以外的映射,则该页面被标记为脏页面,并且只要该页面是脏页面,而另一个进程映射了同一文件的同一区域,则该进程之前写入的数据不会被归零并保留一段时间,这一点是否正确这些事项的最终参考是POSIX,其在mmap的基本原理部分中必须说明: 函数的作用是:映射一个内存区域 大于对象的当前大小。[…打断关于 如果可能的话,发送SIGBUS,即当访问超出末尾的页面时 文件的…]写入的数据可能会丢失,而读取的数据可能不会丢失 反映对象中的实际数据
因此,POSIX说这样做可能会导致数据丢失。此外,可移植性充其量也值得怀疑(想想没有MMU系统、与hugepages的交互、具有不同页面大小的平台……猜测一下,如果文件的一部分已经映射到物理页面,任何映射该文件的进程都会将相同的物理页面映射到其地址空间。因此,对该页面的任何更改(无论是文件的一部分还是结束部分)都将对映射该文件的所有进程可见。@1201程序是的,这就是可以观察到的。但这是否与合同中规定的内容相矛盾。对于不是页面大小倍数的文件,当mapped@wildplasser你能不能把你所说的地图扩大一点。我可以猜测,即使页面很脏,它也会被视为文件的一部分。当它被清除时,EOF之外的数据被归零。对吗?不太对。文件页已经被映射(即使映射到不同的进程中),因此不需要将多余的字节归零。页面==脏在这里是完全不相关的。您可以得到映射(映射时达到当前大小)当文件长度是页面大小的倍数时,似乎会引发SIGBUS,然后当尝试访问超出它的某个区域时,页面错误处理程序会引发信号(这只是我根据Linux上的可观察行为猜测的)