如何获取共享内存中的共享对象
我们的应用程序依赖于外部第三方提供的配置(包括自定义驱动/决策功能),可作为 .so 文件加载。
独立地,它使用一块共享内存与外部 CGI 模块协作,其中几乎所有易失性状态都被保留,以便外部模块可以读取它并在适用的情况下修改它。
问题是 CGI 模块也需要来自 .so 的大量永久配置数据,并且主应用程序在两个内存区域之间执行大量完全不必要的复制以使数据可用。这个想法是将整个共享对象加载到共享内存中,并使其直接可供 CGI 使用。问题是:怎么办?
- dlopen 和 dlsym 不提供任何用于分配 SO 文件加载位置的工具。
- 我们尝试了 shmat()。它似乎只有在某些外部 CGI 实际尝试访问共享内存时才起作用。然后,所指向的区域就显得私密,就好像它从未被共享过一样。也许我们做错了什么?
- 在每个需要它的脚本中加载 .so 是毫无疑问的。该结构的庞大规模,与调用频率相关(某些脚本每秒调用一次以生成实时更新),而且这是一个嵌入式应用程序,因此无法使用。
- 简单地 memcpy() 将 .so 转换为 shm 也不好 - 某些结构和所有函数都通过指针互连。
Our app depends on an external, 3rd party-supplied configuration (including custom driving/decision making functions) loadable as .so file.
Independently, it cooperates with external CGI modules using a chunk of shared memory, where almost all of its volatile state is kept, so that the external modules can read it and modify it where applicable.
The problem is the CGI modules require a lot of the permanent config data from the .so as well, and the main app performs a whole lot of entirely unnecessary copying between the two memory areas to make the data available. The idea is to make the whole Shared Object to load into Shared Memory, and make it directly available to the CGI. The problem is: how?
- dlopen and dlsym don't provide any facilities for assigning where to load the SO file.
- we tried shmat(). It seems to work only until some external CGI actually tries to access the shared memory. Then the area pointed to appears just as private as if it was never shared. Maybe we're doing something wrong?
- loading the .so in each script that needs it is out of question. The sheer size of the structure, connected with frequency of calls (some of the scripts are called once a second to generate live updates), and this being an embedded app make it no-go.
- simply memcpy()'ing the .so into shm is not good either - some structures and all functions are interconnected through pointers.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用共享内存时首先要记住的是,相同的物理内存很可能作为不同的地址映射到两个进程的虚拟地址空间中。这意味着如果在数据结构中的任何地方使用指针,它们都会导致问题。一切都必须通过索引或偏移量才能正常工作。要使用共享内存,您必须清除代码中的所有指针。
加载 .so 文件时,仅加载 .so 文件代码的一份副本(因此称为共享对象)。
fork
也可能是你的朋友。大多数现代操作系统都实现写时复制语义。这意味着,当您fork
时,只有当一个进程写入给定的数据段时,您的数据段才会被复制到单独的物理内存中。The first thing to bear in mind when using shared memory is that the same physical memory may well be mapped into the two processes virtual address space as different addresses. This means that if pointers are used anywhere in your data structures, they are going to cause problems. Everything must work off an index or an offset to work correctly. To use shared memory, you will have to purge all the pointers from your code.
When loading a .so file, only one copy of the .so file code is loaded (hence the term shared object).
fork
may also be your friend here. Most modern operating systems implement copy-on-write semantics. This means that when youfork
, your data segments are only copied into separate physical memory when one process writes to the given data segment.我想最简单的选择是使用内存映射文件,尼尔已经提出了这一点。如果此选项不能很好地填充,替代方法是定义专用分配器。这里有一篇关于它的好论文: Creating STL Containers in Shared Memory
还有一篇出色的 Ion Gaztañaga 的论文带有
shared_memory_object< 的 Boost.Interprocess
库/code> 和相关功能。 Ion 向 C++ 标准化委员会提出了未来 TR 的解决方案: C++ 的内存映射文件和共享内存
什么可能表明它是值得考虑的解决方案。
I suppose the easiest option would be to use memory mapped file, what Neil has proposed already. If this option does not fill well, alternative is to could be to define dedicated allocator. Here is a good paper about it: Creating STL Containers in Shared Memory
There is also excellent Ion Gaztañaga's Boost.Interprocess library with
shared_memory_object
and related features. Ion has proposed the solution to the C++ standardization committee for future TR: Memory Mapped Files And Shared Memory For C++what may indicate it's worth solution to consider.
正如您所发现的,将实际的 C++ 对象放入共享内存中是非常非常困难的。我强烈建议您不要这样做 - 将需要共享的数据放入共享内存或内存映射文件中要简单得多,并且可能更加健壮。
Placing actual C++ objects in shared memory is very, very difficult, as you have found. I would strongly recommend you don't go that way - putting data that needs to be shared in shared memory or a memory mapped file is much simpler and likely to be much more robust.
您需要实现对象的 序列化
序列化函数会将您的对象转换为字节,然后您可以在 SharedMemory 中写入字节并让您的 CGI 模块将字节反序列化回对象。
You need to implement object's Serialization
Serialization function will convert your object into bytes, then you can write bytes in SharedMemory and have your CGI module to deserialize bytes back to object.