当 2 个程序映射同一个文件时,mmap 如何工作
How does mmap work when 2 programs map the same file
我在查看 man mmap 时试图了解 mmap
的工作原理。
据我了解,它向页面 table 添加了一个映射,该映射在文件和虚拟地址(即给定的地址 void *addr
)之间进行映射
那么,当 2 个程序映射同一个文件时会发生什么?
页面中是否有 2 个条目 table,每个程序一个?
实际系统实现不同。冒着过度简化的风险(并在此处省略分页):
mmap 会将物理页框映射到文件。
So, what happens when 2 programs map the same file? Are there 2 entries in the page table, one for each program?
如果两个进程(P 和 Q)映射到同一个文件,那么 P 和 Q 将各自拥有自己的页面 table;每个页面 table 将具有映射到相同物理页框的条目(可以映射到 P 和 Q 中的不同地址)。
So, what happens when 2 programs map the same file? Are there 2 entries in the page table, one for each program?
在现代操作系统中,每个进程都有自己的内存页 table,它可能指向与其他用户和内核进程共享的物理内存页。
With MAP_SHARED
, this mapping is shared: updates to the mapping are visible to other processes that map this file, and are carried through to the underlying file. The file may not actually be updated until msync(2) or munmap() is called.
这看起来很有趣,但有很多注意事项:
两个进程为同一个文件映射的实际页面可能驻留在每个进程中的相同地址或不同地址,存储指向此 shared[=36= 的指针] 内存可能不允许其他进程使用它们,因为它们可能指向不一致的地址。
实现可能对两个映射使用相同的物理内存页,也可能不使用相同的物理内存页:出于微妙的原因(缓存策略,不同步读取...),即使它是相同的物理内存,一个进程对其内存所做的修改可能不会立即反映在另一进程的内存中。
因此修改可能对映射文件或通过 read
或 FILE*
流 API.
读取文件的其他进程可见,也可能不可见
如果其中一个进程调用 msync()
,修改应该在所有地图和文件的所有未读部分中可见,请记住 FILE*
流 APIs 可能在内部非共享缓冲区中缓冲了一些数据:不会反映在此区域的修改。
结论:使用这些机制来实现进程间通信是有风险且不可靠的。该行为可能取决于系统特定的特征,例如 OS 策略、CPU 和缓存架构、使用的 RAM 类型、时钟速度,谁知道还有什么。依靠经过验证的 APIs 更安全,这些 APIs 确实可以使用 mmapped 内存实现,但前提是它知道提供正确的语义。
我在查看 man mmap 时试图了解 mmap
的工作原理。
据我了解,它向页面 table 添加了一个映射,该映射在文件和虚拟地址(即给定的地址 void *addr
)之间进行映射
那么,当 2 个程序映射同一个文件时会发生什么? 页面中是否有 2 个条目 table,每个程序一个?
实际系统实现不同。冒着过度简化的风险(并在此处省略分页):
mmap 会将物理页框映射到文件。
So, what happens when 2 programs map the same file? Are there 2 entries in the page table, one for each program?
如果两个进程(P 和 Q)映射到同一个文件,那么 P 和 Q 将各自拥有自己的页面 table;每个页面 table 将具有映射到相同物理页框的条目(可以映射到 P 和 Q 中的不同地址)。
So, what happens when 2 programs map the same file? Are there 2 entries in the page table, one for each program?
在现代操作系统中,每个进程都有自己的内存页 table,它可能指向与其他用户和内核进程共享的物理内存页。
With
MAP_SHARED
, this mapping is shared: updates to the mapping are visible to other processes that map this file, and are carried through to the underlying file. The file may not actually be updated until msync(2) or munmap() is called.
这看起来很有趣,但有很多注意事项:
两个进程为同一个文件映射的实际页面可能驻留在每个进程中的相同地址或不同地址,存储指向此 shared[=36= 的指针] 内存可能不允许其他进程使用它们,因为它们可能指向不一致的地址。
实现可能对两个映射使用相同的物理内存页,也可能不使用相同的物理内存页:出于微妙的原因(缓存策略,不同步读取...),即使它是相同的物理内存,一个进程对其内存所做的修改可能不会立即反映在另一进程的内存中。
因此修改可能对映射文件或通过 read
或 FILE*
流 API.
如果其中一个进程调用 msync()
,修改应该在所有地图和文件的所有未读部分中可见,请记住 FILE*
流 APIs 可能在内部非共享缓冲区中缓冲了一些数据:不会反映在此区域的修改。
结论:使用这些机制来实现进程间通信是有风险且不可靠的。该行为可能取决于系统特定的特征,例如 OS 策略、CPU 和缓存架构、使用的 RAM 类型、时钟速度,谁知道还有什么。依靠经过验证的 APIs 更安全,这些 APIs 确实可以使用 mmapped 内存实现,但前提是它知道提供正确的语义。