用于读取input文件的内存映射文件有多安全?

将input文件映射到内存中,然后直接从映射的内存页面parsing数据可以是从文件中读取数据的方便有效的方法。

但是,除非可以确保没有其他进程写入映射文件,否则这种做法似乎也基本上是不安全的,因为如果底层文件被另一个进程写入,即使私有只读映射中的数据也可能发生更改。 (POSIX例如没有指定 “在MAP_PRIVATE映射build立之后对底层对象的修改是否通过MAP_PRIVATE映射可见”)。

如果想要在映射文件的外部更改的情况下使代码安全,则只能通过易失性指针访问映射的内存,然后非常小心如何读取和validationinput,这似乎不切实际很多用例。

这个分析是否正确? 内存映射API的文档通常提到这个问题,如果有的话,所以我想知道我是否错过了一些东西。

这不是一个真正的问题。

是的,另一个进程可能会修改文件,当你有它的映射,是的,你可能会看到修改。 甚至有可能 ,因为几乎所有的操作系​​统都有统一的虚拟内存系统,所以除非有人要求无缓冲的写操作,否则如果没有通过缓冲区缓存就没有办法编写,没有办法在没有人持有映射的情况下看到变化。
这甚至不是一件坏事。 事实上,如果你看不到变化,那会更令人不安。 由于准确映射的文件成为您的地址空间的一部分,因此您可以看到文件的更改。

如果您使用传统的I / O(例如read ),则在读取文件时,仍然可以修改文件。 换一种方式, 将文件内容复制到内存缓冲区并不总是安全的 。 只要read不会崩溃,它是“安全的”,但不能保证数据的一致性。
除非你使用readv ,否则你不能保证原子性(即使readv你也不能保证你在内存中的内容与磁盘上的内容是一致的,或者在两次readv之间没有变化)。 有人可能会修改两个read操作之间的文件,甚至当你在它的中间。
这不仅仅是没有得到正式保证,而是“可能仍然有效”的东西 – 相反,例如在Linux下,写入显然不是原子的。 甚至不是偶然的。

好消息:
通常,进程只是打开一个任意的随机文件,并开始写入。 当发生这种情况时,它通常是属于进程的知名文件(例如日志文件),或者是明确告诉进程写入的文件(例如保存在文本编辑器中),或者进程创建一个新的文件(例如,编译器创建一个目标文件),或者该过程仅仅追加到一个现有的文件(例如db日志,当然还有日志文件)。 或者,一个进程可能原子地替换另一个文件(或取消链接)。

在任何情况下,整个可怕的问题归结为“没有问题”,因为要么你知道会发生什么(所以这是你的责任),要么就是没有干扰地无缝工作。

如果您真的不喜欢其他进程可能写入文件的可能性,则可以在创建文件句柄时简单地忽略Windows下的FILE_SHARE_WRITE 。 POSIX使得它更复杂一些,因为你需要为描述符强制锁定一个强制性的锁定,这在每个系统上都是不必要的,或者是100%可靠的(比如在Linux下)。

从理论上讲,如果有人在阅读文件时修改了文件,那么可能会遇到麻烦。 在实践中:你正在阅读的字符,没有别的:没有指针,或任何可能让你陷入困境。 实际上……在形式上,我认为这还是一个不确定的行为,但我认为你不必担心。 除非修改是非常小的,否则你会得到很多编译错误,但这是关于它的结束。

可能导致问题的一种情况是文件缩短了。 我不确定会发生什么,当你读到最后。

最后:系统不会随意打开和修改文件。 这是一个源文件; 这将是一个白痴程序员谁做,他应得的。 在任何情况下,您的未定义的行为都不会损坏系统或其他人的文件。

还要注意,大多数编辑工作在一个私人的副本; 当回写时,他们通过重命名原来的,并创建一个新的文件。 在Unix下,一旦你打开了mmap文件,所有重要的是inode号码。 而当编辑器重命名或删除文件,你仍然保持你的副本。 修改后的文件将得到一个新的inode。 唯一需要担心的是如果有人打开文件进行更新,然后进行修改。 没有太多的程序在文本文件上做这件事,除了追加额外的数据。

所以在正式的情况下,存在一定的风险,我认为你不必担心。 (如果你真的是偏执的话,你可以关掉写授权,而如果真的有一个敌方特工出来,你可以把它重新打开。)