gpt4 book ai didi

c++ - 当多个进程使用该段时,Posix 共享内存使用 mremap 调整大小

转载 作者:IT王子 更新时间:2023-10-29 01:03:21 29 4
gpt4 key购买 nike

我将一些数据存储在多个进程使用的共享内存数组中。在某些时候,我想扩大阵列。

假设进程之间已经有同步机制

最初,进程 1 将创建段,进程 2 将打开它。

过程1
shm_open() O_CREATftruncate()mmap() MAP_SHARED
过程2
shm_open()mmap()
在某一时刻,一个进程想要扩大数组并调整共享段的大小。

处理 1 次调用
ftruncate()mremap() MREMAP_MAYMOVE
应通知进程 2 调整大小并调用 mremap()也要更新它自己的虚拟地址?

如果必须通知进程 2,我正在考虑使用一些元数据打开第二个共享内存段,例如表的容量和互斥锁。
每个进程最初从共享内存中存储表的容量,并在每个操作中根据共享内存元数据值检查本地值。如果值已更改,它将调用 mremap()
如果 mremap(),这是正确的方法吗?调整大小后必须在每个进程上调用?

最佳答案

Shall Process 2 be notified of the resize and call mremap() to update it’s own virtual address too ?



进程 2 已经映射了共享内存段的特定区域。另一个增加段大小的过程不会使该映射无效。这也不会改变在进程 2 中映射的共享内存段的区域——即使进程 2 最初映射了整个段,超出段原始结尾的部分也不会自动映射到进程 2 中。

因此,只要进程 2 不需要访问该段的其他页面,它就根本不需要更新其映射。然而,如果它想访问额外的共享内存,那么它确实需要更新它的映射。它可以尝试通过特定于 Linux 的 mremap() 来做到这一点。 ,或通过 munmap()其次是 mmap() .后者要求它仍然具有该段的打开文件描述符。无论哪种方式,都可能无法映射从相同基地址开始的更大空间。就此而言,可能根本无法映射更大的空间,无论是否有任何其他进程能够这样做。

关于映射的基地址

默认情况下, mremap()将尝试修改映射区域而不更改其基地址,并且 munmap() + mmap()可以通过从 mmap() 请求原始基地址来要求做同样的事情。并通过 MAP_FIXED旗帜。如果无法在该地址扩展映射,这些将失败。在后一种情况下,这也将使该段完全未映射。

您可以通过指定 MREMAP_MAYMOVE 来允许选择新的基地址。其中 mremap()标志,或避免指定 MAP_FIXEDmmap() .当扩展同一地址的映射失败时,这种尝试可能会成功,但 请注意基地址的更改会使该进程指向原始映射的所有指针无效,无论存储在何处。

因此,如果您要提供基地址的更改,那么最好不要将任何指针存储到映射中,除了指向基地址的单个指针。在这种情况下,通过该指针或相对于它的其他方式访问内容。

If Process 2 has to be notified I’m thinking of opening a second shared memory segment with some metadata e.g the table’s capacity and a mutex. Each process stores the table’s capacity initially from shared memory and on each operation checks the local value against the shared memory metadata value. If the value has changed it will call mremap()

Is this a proper way to do this if mremap() has to be called on each process after resizing?



如果您正确同步对元数据的访问,您的方案听起来可行。事实上,虽然可能有其他原因这样做,但问题中没有任何内容表明甚至有必要将元数据放在单独的共享内存段中。扩展不应影响段的原始页面的内容或其在进程 2 中的映射,因此如果元数据存储在那里,那么进程 2 应该仍然能够在扩展后访问它们。

但是请注意,如果用于同步对段的访问的互斥锁、信号量或类似物在该段内,则您需要考虑 mremap() 的事实。可以移动它,和 munmap()/ mmap()对于 munmap() 的情况,您将需要更复杂的恢复方案。成功但后续 mmap()失败。

在理解所有这些时,记住以下几点可能是有用的
  • 共享内存段的大小是段的一个属性,由内核维护。
  • 段的每个映射的特征,包括映射的区域(特定范围的页)和它映射到的基地址,是特定进程的属性,独立于相同或其他段中的所有其他映射过程。
  • 段的每个映射的特征也很大程度上独立于段本身。特别是,映射区域的偏移量和大小不会随着片段大小的变化而变化。
  • 关于c++ - 当多个进程使用该段时,Posix 共享内存使用 mremap 调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49266193/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com