【问题标题】:How does mmap work when 2 programs map the same file当 2 个程序映射同一个文件时 mmap 是如何工作的
【发布时间】:2016-05-08 10:07:04
【问题描述】:

我在查看man mmap 时试图了解mmap 的工作原理。

据我了解,它向页表添加了一个映射,该映射在文件和虚拟地址之间进行映射(这是给定的地址 void *addr

那么,当两个程序映射同一个文件时会发生什么? 页表中是否有 2 个条目,每个程序一个?

【问题讨论】:

  • 每个程序基本上都有单独的MMU配置。只是两个进程映射了同一个页面。
  • 当一个进程尝试写入时,是写入主存(RAM)还是直接写入文件(硬盘)?
  • @Lee:在我看来,您确实了解。这正是它的意思。
  • @Lee:不一定。 在调用 msync(2) 或 munmap() 之前,该文件实际上可能不会被更新。 修改可能对映射文件或通过 read 或读取文件的其他进程可见,也可能不可见FILE* 流 API。如果其中一个进程调用msync(),则修改应该在所有映射中以及文件的所有尚未读取的部分中可见,请记住FILE* 流式API 可能已在内部非共享缓冲区中缓冲了一些数据。跨度>
  • @john 两者都不是。我建议阅读 MMU 的功能。也许现代操作系统为内存保护做了什么。最后,我建议阅读 mmap() 的手册页。

标签: c linux mmap virtual-memory page-tables


【解决方案1】:

那么,当两个程序映射同一个文件时会发生什么?页表中是否有 2 个条目,每个程序一个?

在现代操作系统中,每个进程都有自己的内存页表,它可能指向与其他用户和内核进程共享的物理内存页。

使用MAP_SHARED,此映射是共享的:映射的更新对映射此文件的其他进程可见,并传递到底层文件。在调用 msync(2) 或 munmap() 之前,该文件可能不会真正更新。

这看起来很有趣,但有很多警告:

  • 两个进程为同一个文件映射的实际页面可能驻留在每个进程的相同地址或不同地址,将指针存储到此共享内存中可能不允许另一个使用它们的过程,因为它们可能指向不一致的地址。

  • 实现可能对两个映射使用相同的物理内存页:出于微妙的原因(缓存策略、不同步读取...),即使它是相同的物理内存,也由一个人完成修改进程对其内存的处理可能不会立即反映在其他进程的内存中。

因此修改可能对映射文件或通过readFILE* 流API 读取文件的其他进程可见,也可能不可见。

如果其中一个进程调用 msync(),则修改应该在所有映射中以及文件的所有尚未读取的部分中可见,请记住 FILE* 流 API 可能已在内部非共享缓冲区中缓冲了一些数据: 这方面的修改不会反映。

结论:使用这些机制来实现进程间通信是有风险和不可靠的。行为可能取决于系统特定的特性,例如操作系统策略、CPU 和缓存架构、正在使用的 RAM 类型、时钟速度以及谁知道还有什么。依靠经过验证的 API 更安全,这些 API 确实可以使用映射内存实现,但前提是它知道提供正确的语义。

【讨论】:

    【解决方案2】:

    实际的系统实现是不同的。有过度简化的风险(并在此处省略分页):

    mmap 会将物理页框映射到文件。

    那么,当两个程序映射同一个文件时会发生什么?页表中是否有 2 个条目,每个程序一个?

    如果两个进程(P 和 Q)映射到同一个文件,那么 P 和 Q 将各自拥有自己的页表;每个页表都会有条目映射到同一个物理页框(可以映射到 P 和 Q 内的不同地址)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2014-10-01
      • 1970-01-01
      • 2019-07-08
      • 2017-09-02
      • 2021-06-29
      相关资源
      最近更新 更多