Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将文件映射到内存,并在文件末尾写入_C_Linux_File Io_Linux Kernel_Memory Mapped Files - Fatal编程技术网

C 将文件映射到内存,并在文件末尾写入

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

我正在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);
    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上的可观察行为猜测的)