Search code examples
c++boostmmapmemory-mapped-filesboost-interprocess

Growing Boost.Interprocess memory mapped file with single writer


My question is about growing memory-mapped regions with Boost.Interprocess, in the context of a single writer process and multiple reader processes. Is it OK to use managed_mapped_file::grow from the writer, assuming it's acceptable for the readers not to be updated of the change of the map's size? My assumption is that the reader's maps would stay valid, and then I could remap the readers with the updated size when I need them to pick up the latest changes from the writer. Is this correct?

The Growing managed segments section of the documentation says:

Once a managed segment is created the managed segment can't be grown. The limitation is not easily solvable: every process attached to the managed segment would need to be stopped, notified of the new size, they would need to remap the managed segment and continue working. [...]

This makes me think that I can grow as long as I'm fine with the readers not being updated right away. However, the documentation goes on saying:

On the other hand, Boost.Interprocess offers off-line segment growing. What does this mean? That the segment can be grown if no process has mapped the managed segment. If the application can find a moment where no process is attached it can grow or shrink to fit the managed segment. [...] managed_mapped_file also offers a similar function to grow or shrink_to_fit the managed file. Please, remember that no process should be modifying the file/shared memory while the growing/shrinking process is performed. Otherwise, the managed segment will be corrupted.

This makes me think that I can't do what I want to do, but I don't understand why it would not work.


Solution

  • Let's make a careful distinction between shared_memory_object (which is really low-tech and un-imposing) and managed_shared_memory/managed_mapped_file (which both use a segment_manager).

    You are using the latter.


    "assuming it's acceptable for the readers not to be updated of the change of the map's size":

    I don't see how this assumption can hold.

    The managed segment constitutes, in essence, an auxiliary memory heap with its associated control structures.

    It makes sense for the control structure to include details such as the actual extents of that "heap". Since the control structures are in the shared memory, they must be in the section already mapped into reading processes, too.

    Changing the size of the memory segment would change values in that control structure which is visible from all processes mapping the same shared memory. This would obviously wreak havoc in processes that don't actually have enough memory mapped to satisfy the new extents (leading to page faults, at best).

    Now, I can imagine a very smart implementation that circumvents the need for such control information (like e.g. a classical free block list with a sentinel value). But I don't expect Boost Interprocess to have taken this route¹, and the text you quoted strongly suggests that the design didn't cater for this kind of flexibility.

    Is it OK to use managed_mapped_file::grow from the writer, assuming it's acceptable for the readers not to be updated of the change of the map's size?

    No it's not OK.

    My assumption is that the reader's maps would stay valid, and then I could remap the readers with the updated size when I need them to pick up the latest changes from the writer. Is this correct?

    The /maps/ will be fine, no doubt (depending on how grow is implemented, but I think I've confirmed this experimentally before). The problem is with the segment_manager that operates on top. This is the one that is going to be confused.

    ¹ pure Fingerspitzengefühl