我想在多个进程之间使用共享内存,并且希望能够继续使用原始指针(和 STL 容器)。
为此,我使用映射到固定地址的共享内存:
segment = new boost::interprocess::managed_shared_memory(
boost::interprocess::open_or_create,
"MySegmentName",
1048576, // alloc size
(void *)0x400000000LL // fixed address
);
选择这个固定地址的好策略是什么?例如,我应该使用一个相当高的数字来减少堆空间不足的机会吗?
最佳答案
这是一个难题。如果您要 fork 单个程序来创建子级,并且只有父级和子级会使用内存段,请确保在 fork 之前映射它。 child 会自动从他们的 parent 继承映射,不需要使用固定地址。
如果不是,那么首先要考虑的是您是否真的需要使用原始 STL 容器而不是 boost 进程间容器。您已经在使用 boost interprocess 来分配共享内存段表明您使用 boost 没有任何问题,所以我能想到使用 STL 容器的唯一优势是您不必移植现有代码。请记住,要使其与固定地址一起工作,容器及其包含的指针(假设您正在使用指针容器)将需要保存在共享内存空间中。
如果你确定这是你想要的,你就必须想办法让他们协商一个地址。请记住,操作系统可以拒绝你想要的固定内存地址 .如果该地址处的页面已映射到内存或已分配,它将拒绝该地址。因为不同的程序会在不同的时间分配不同数量的内存,所以哪些页面可用,哪些页面不可用因程序而异。
所以你需要让程序就内存地址达成共识。这意味着可能必须尝试并拒绝多个地址。如果可能在启动后的某个时间对新程序感兴趣,寻求共识将不得不重新开始 .算法看起来像这样:
要确定 A 应该建议的地址,您可以让 A 映射一个非固定的内存段,查看它映射到的地址,然后建议该地址。如果不满意,请映射另一个部分并提出它。您将需要在某个时候取消映射段,但您不能立即取消映射它们,因为如果取消映射然后重新映射相同大小的段,操作系统可能会一遍又一遍地为您提供相同的地址。 请记住,您可能永远无法达成共识 ;不能保证在所有进程的公共(public)位置有足够大的段。如果您的程序全部独立使用几乎所有内存,例如它们是否由大量交换备份(尽管如果您足够关心性能以使用共享内存,希望您避免交换),则可能会发生这种情况。
以上所有内容都假设您处于相对受限的地址空间中。 如果您使用的是 64 位,这可以工作 .大多数计算机的 RAM + 交换将远小于 64 位允许的值,因此您可以将内存映射到所有进程不太可能已经映射的非常远的固定地址。我建议至少 2^48,因为当前的 64 位 x86 处理器每个都不会超出该范围(尽管指针是 64 位,但您只能插入 48 位允许的 RAM,仍然有很多撰写本文的时间)。尽管智能堆分配器没有理由不能利用地址空间的巨大优势来减少其簿记工作,但要真正强大,您仍然需要建立共识。请记住,您至少希望地址是可配置的——即使我们很快就没有那么多内存,从现在到那时,其他人可能会有相同的想法并选择您的地址。
要进行双向通信,您可以使用任何套接字、管道或其他共享内存段。您的操作系统可能提供其他形式的 IPC。但是强烈考虑一下,如果您只使用 boost 进程间容器,您现在可能会引入更多的复杂性;)
关于c++ - 如何为共享内存映射选择固定地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5939578/