Ste*_*orf 11 c c++ windows posix memory-mapped-files
将输入文件映射到存储器然后直接从映射的存储器页面解析数据可以是从文件读取数据的方便且有效的方式.
但是,除非您可以确保没有其他进程写入映射文件,否则这种做法似乎从根本上说是不安全的,因为即使私有只读映射中的数据可能会在另一个进程写入基础文件时发生更改.(POSIX例如,未指定 "在建立MAP_PRIVATE映射后是否通过MAP_PRIVATE映射可以看到对基础对象的修改".)
如果您希望在对映射文件进行外部更改时使代码安全,则必须仅通过易失性指针访问映射内存,然后非常小心您如何读取和验证输入,这似乎不切实际.许多用例.
这个分析是否正确?内存映射API的文档通常只在传递中提到这个问题,如果有的话,所以我想知道我是否遗漏了一些东西.
这并不是真正的问题。
是的,当您映射该文件时,另一个进程可能会修改该文件,是的,您有可能会看到这些修改。甚至有可能,因为几乎所有操作系统都有统一的虚拟内存系统,所以除非有人请求无缓冲的写入,否则就无法在不经过缓冲区高速缓存的情况下进行写入,并且如果没有持有映射的人看到更改,就无法进行写入。
这甚至不是一件坏事。事实上,如果你看不到这些变化,会更令人不安。由于当您映射文件时,文件准成为地址空间的一部分,因此您看到文件的更改是非常有意义的。
如果您使用常规 I/O(例如read),那么在您读取文件时,其他人仍然可以修改该文件。换句话说,将文件内容复制到内存缓冲区在存在修改的情况下并不总是安全的。它是“安全”的,read不会崩溃,但它不能保证您的数据是一致的。
除非您使用readv,否则您无法保证原子性(即使readv您无法保证内存中的内容与磁盘上的内容一致,或者在两次调用之间不会改变readv)。有人可能会在两次操作之间修改文件read,甚至在您正在进行操作时也可能会修改该文件。
这不仅仅是没有正式保证的东西,而且“可能仍然有效”——相反,例如在 Linux 下写入显然不是原子的。甚至不是偶然。
好消息:
通常,进程不只是打开任意随机文件并开始写入它。当发生这种情况时,通常是属于该进程的众所周知的文件(例如日志文件),或者是您明确告诉进程写入的文件(例如保存在文本编辑器中),或者是进程创建一个新文件(例如编译器创建一个目标文件),或者该过程仅附加到现有文件(例如数据库日志,当然还有日志文件)。或者,进程可能会自动用另一个文件替换一个文件(或取消链接)。
在每种情况下,整个可怕的问题都归结为“没问题”,因为要么你很清楚会发生什么(所以这是你的责任),要么它无缝地工作而不会受到干扰。
如果您确实不喜欢在映射文件时另一个进程可能FILE_SHARE_WRITE写入文件的可能性,则可以在创建文件句柄时在 Windows 下简单地省略。POSIX 使其变得更加复杂,因为您需要fcntl强制锁定的描述符,而这在每个系统上(例如,在 Linux 下)不一定支持或 100% 可靠。
| 归档时间: |
|
| 查看次数: |
1707 次 |
| 最近记录: |