【问题标题】:Non-Boost STL allocator for inter-process shared memory?用于进程间共享内存的非 Boost STL 分配器?
【发布时间】:2012-09-18 17:56:28
【问题描述】:

由于我工作的政策,我无法使用高于 1.33.1 的 Boost 版本,也无法使用高于 4.1.2 的 GCC 版本。是的,这是垃圾,但我对此无能为力。 Boost 1.33.1 不包含进程间库。

也就是说,我的一个项目需要将std::map(或更可能是std::unordered_map)放入共享内存。当进程由单个进程(“服务器”)加载并由许多其他进程读取时,它只被写入/修改一次。我以前没有做过共享内存 IPC,所以这对我来说是一个相当新的领域。我查看了shmget(),但似乎我不能持续使用相同的共享内存键进行分配(我认为 STL 容器分配器需要)。

还有其他使用共享内存的NON-BOOST STL 分配器吗?

编辑:已经做过了。 Dr. Dobbs had an article on how to do this exactly back in 2003,我开始用它作为参考。但是,代码列表不完整,指向它们的链接会重定向到主站点。

编辑编辑:我不只是重写 Boost.Interprocess 的唯一原因是因为涉及的代码量。我只是想知道是否有专门针对 POSIX 共享内存的相对简短和简洁的东西,我可以从头开始重写,因为网络之间的数据传输也需要经过多天的审批流程......

【问题讨论】:

  • 哎哟。听起来你在自找麻烦,我不会在共享内存中放置std::map,提升或不提升。你确定这是解决这个问题的最好方法吗?也许是更干净的消息传递解决方案?
  • 好吧,我不确定。我正在转换的软件最初是用 Python 编写的,并使用多处理库将字典存储在共享内存中。我尝试查看库的 C 实现,但无法弄清楚字典代理实际上是如何使用共享内存的,但这很大程度上与组织不善和我放弃搜索有关。还应注意,此映射是一次写入的只读结构。它从配置文件加载默认值并将它们存储在内存中,直到进程重新启动。之后没有对值进行任何更改。
  • 您对这张地图的天花板尺寸有合理的期望吗? (即元素数量和其中占用的空间?)
  • 所以你不能使用最新的 Boost 版本,但只要它包含所需的功能,就可以使用任何随机的开源库?我在这里闻到了老鼠的味道……无论如何。包含指针的对象不能放在共享内存中。您需要相对内存偏移量。 Boost IPC lib 不允许您将std::map 放在共享内存中(什么都不会),它提供了自己的map 版本。您需要创建自己的。由于您的数据结构是 WORM,因此您可以只使用排序数组。没有指针。
  • @n.m.我不能只使用任何开源库。我们受到this document 的限制。而且我知道不能使用指针。这就是我想要一个 STL 分配器的原因,所以如果需要,我也可以将它用于字符串。至于无法将 STL 容器放在共享内存中,Dr. Dobbs did it in 2003 但它们的存档代码列表不完整。

标签: c++ ipc shared-memory allocator


【解决方案1】:

指针在共享内存中不起作用,除非您无法将共享内存固定在固定地址(在所有进程中都是一致的)。因此,您需要特定的类,它们要么是连续的(无指针),要么在映射共享内存的内存区域中具有偏移量(而不是指针)。

我们在非常相似的情况下使用共享内存:一个进程计算一组数据,将其放入共享内存中,然后向其他进程发出信号,它们可以将内存映射到自己的地址空间;之后的记忆永远不会改变。

我们采用的方法是使用 POD 结构 (*)(其中一些包括用于字符串存储的 char xxx[N]; 属性)。如果你真的可以限制你的弦,你就是金子。就map 而言:只读存储效率低下=> 排序数组性能更好(为​​内存局部性欢呼)。所以我建议这样做:

struct Key {
    enum { Size = 318 };
    char value[Size];
};

struct Value {
    enum { Size = 412 };
    enum K { Int, Long, String };
    K kind;
    union { int i; long l; char string[Size]; } value;
};

然后只需有一个 std::pair<Key, Value> 数组,您可以对其进行排序 (std::sort) 并在其上使用 std::lower_bound 进行搜索。显然,您需要为键编写一个比较运算符:

bool operator<(Key const& left, Key const& right) {
    return memcmp(left.value, right.value, Key::Size) < 0;
}

我同意 enum + union 技巧比 boost 变体更不吸引人(界面方面)......这取决于你如何让界面变得更好。

(*) 实际上,不需要纯 POD。例如,拥有私有属性、构造函数和复制构造函数是完全可以的。所需要的只是避免间接(指针)。

【讨论】:

  • 我不认为限制字符串大小是个问题。至于您的第一点,我认为这就是在这种情况下使用 STL 分配器的重点:使用 shmget() 分配,然后在消费者进程中使用与 shmat() 相同的内存键将自己的内存映射到共享内存。你的意思是这行不通?
  • @jvstech:我不是专家,所以对这些建议持保留态度,但是 Boost.Interprocess 竭尽全力“模拟”常规指针语义与基指针的组合(段的开头)+ 偏移量,但这需要使用专用的指针类(例如,参见offset_ptr)。我不确定 just 在标准容器中指定分配器是否能让您到达那里。
  • @jvstech:我特别建议您阅读有关limitations 的信息。
  • 我最担心的是,一些 STL 实现会简单地忽略它们指定的分配器并随意使用内存。
  • 无论如何,我基本上已经将自己降级为与此类似的东西。分配器会很棒,但在那之前,使用它会比等待更新的 boost 安装的授权从 Dr. Dobbs 文章中获取完整代码更快。
【解决方案2】:

简单的解决方法。从 Boost 1.51 创建您自己的“libNotBoost v1.0”。Boost 库允许这样做。因为它不再是 Boost,所以你很好。

【讨论】:

  • 我查看了 1.39.0 的进程间库(我尝试获取策略异常以便我可以安装它)并决定可能实际上与实现我正在转换的软件的整个基础一样多的工作......
  • 我之前尝试过提取提升片段。尽管 boost 确实为您提供了一个有用的工具,但它不仅需要大量工作,而且您不可避免地会得到数十个甚至数百个依赖文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 2017-05-14
相关资源
最近更新 更多