通过内存共享 C++ 对象

Posted

技术标签:

【中文标题】通过内存共享 C++ 对象【英文标题】:shared C++ object through memory 【发布时间】:2014-06-27 07:45:52 【问题描述】:

对于那些熟悉进程间通信的人,我有一个简短的问题。

情况

我有一个程序(程序 A),我可以添加一些代码,但非常有限。这是生成大量数据的主程序。 数据的制定方式是有限的,所以我想创建第二个程序(程序B),因此需要从A到B获取数据。甚至有时会导致A运行一些没有返回值的函数。 我知道命名管道,但是我觉得它们可能很笨重? - 不确定 - 例如,我有以下担忧(可能没有根据):
    数据流 => 转换为二进制 -> 将数据放入内存 -> 服务器读取 -> 转换为字符串 -> 通过可能的 switch 语句确定请求的内容 -> 获取请求的内容 -> 转换为二进制 -> 放置在内存中 -> 由客户端读取并转换为字符串/某种可接受的格式。 它必须在两边都使用基本的 switch 语句,如果您想要除字符串以外的其他信息格式,则需要考虑这一点 一条消息可能必须等待另一条消息完成,因此在同时调用大量消息时它可能会变慢? - 虽然不确定
其他进程间通信方法可能存在同样的问题。

我认为更好的解决方案是创建一个“对象” - 类。并在程序之间共享对象内存地址,从而理论上将A和B“合并”起来:

    编码和解码等问题没有问题 数据只是通过调用函数来请求/调用。 函数返回正确的类型,无需确定正确的类型是什么(即 bool / int / string / double 等)

我知道这也有几个问题,即如果对象被主/另一个访问它的程序从内存位置删除。

问题

解决此问题的最佳方法是什么: C++ 中是否有一个调用选项允许我从内存地址写入和读取?在这一刻:
    我可以访问 A 和 B 之间的同一个对象,但我不能写/读,因为这会引发异常。那么基本上我可以通过简单的调用或者读/写这个对象吗? 我知道 WriteProcessMemory 函数 - 但这不是我想要的 - 即,我不一定要更改内存值,只需访问来自 B 的数据/调用 A 将执行的操作。
有没有简单易行的方法?我知道一种叫做 boost 的东西,但对此一无所知 - 这是我最好的选择吗? -> 即我应该将此作为我的最佳解决方案进行调查吗?

提前感谢您对此问题的任何建议。

【问题讨论】:

“我知道一个叫做 boost”的东西。好的。但最好的办法是使用它:boost.org。还有……惊喜!有一些东西可以帮助您解决问题:Boost.Interprocess 你可以通过管道发送二进制数据就好了。事实上,对于操作系统来说,通过管道的是原始字节流。但是,您想使用正确的序列化格式。 “Cap'n Proto”怎么样,它对您的情况有好处,有线格式与内存中的数据相同。 【参考方案1】:

Boost.Interprocess 有很多方法可以在进程之间共享数据,其中一种是shared_memory

来自 boost 的示例,其中程序充当同一内存对象的服务器或客户端(取决于是否给出参数)

include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstring>
#include <cstdlib>
#include <string>

int main(int argc, char *argv[])

   using namespace boost::interprocess;

   if(argc == 1)  //Parent process
      //Remove shared memory on construction and destruction
      struct shm_remove
      
         shm_remove()  shared_memory_object::remove("MySharedMemory"); 
         ~shm_remove() shared_memory_object::remove("MySharedMemory"); 
       remover;

      //Create a shared memory object.
      shared_memory_object shm (create_only, "MySharedMemory", read_write);

      //Set size
      shm.truncate(1000);

      //Map the whole shared memory in this process
      mapped_region region(shm, read_write);

      //Write all the memory to 1
      std::memset(region.get_address(), 1, region.get_size());

      //Launch child process
      std::string s(argv[0]); s += " child ";
      if(0 != std::system(s.c_str()))
         return 1;
   
   else
      //Open already created shared memory object.
      shared_memory_object shm (open_only, "MySharedMemory", read_only);

      //Map the whole shared memory in this process
      mapped_region region(shm, read_only);

      //Check that memory was initialized to 1
      char *mem = static_cast<char*>(region.get_address());
      for(std::size_t i = 0; i < region.get_size(); ++i)
         if(*mem++ != 1)
            return 1;   //Error checking memory
   
   return 0;

【讨论】:

谢谢彼得。我会试试这个。我以前没有做过共享内存。我的想法是否正确,您可以将对象放置在共享内存位置并提供 A 和 B 都具有对象构造的“原型” - 即两者都引用同一个类并且仅通过在两侧创建指针就可以使用它?还是更像“命名管道”,其中内存被命名,A 和 B 都监视共享内存的变化。我以为是前者。我将进一步调查 Boost。谢谢!!!! @DaClan 可以在共享内存中创建类,但是你必须小心同步问题,看看boost.org/doc/libs/1_55_0/doc/html/interprocess/…(更好的是,花一些时间阅读整个进程间文档,这不是一项简单的任务)【参考方案2】:

简化!

一般来说,shared state 可能是个坏主意,无法很好地测试,并且可能像 global variables 那样对难以管理的架构造成严重破坏。

ØMQ guide 可能会帮助您掌握可能的解决方案。一般来说,如果您没有特殊要求,请使用消息传递。 ØMQ“sockets”速度很快,非常健壮,并且只需要很少的代码就可以开始。

更新:现成的:msgpack-rpc 或 protobuf-remote

【讨论】:

谢谢@Dmitry。我知道这个解决方案。但是除非我弄错了,否则您仍然会遇到编码和解码问题,因为有 100 个函数要调用,所以您必须确定发送的消息实际调用了哪个函数 - 我已经开始了之前使用命名管道的类似根,但编码似乎很麻烦,因为您需要在服务器端和客户端编写编码和解码函数。这可能是简单的解决方案!但是写起来是否一定会在性能/效率上很快? - 共享课程不是更好的解决方案吗? 有简单的解决方案:RPC:msgpack-rpc 或protobuf-remote 通过适当的关注点分离,您无需编写编码和解码功能。您的接口声明将同时被编码和解码的实现以及C++代码使用 或“Cap'n Proto – RPC” @datenwolf 我对 Cap'n Proto 一点也不熟悉。我也会对此进行调查。谢谢!【参考方案3】:

您是为客户开发软件,还是只为自己开发数据分析软件?如果只是为了你自己,你可以将数据写入你的硬盘,然后将你的分析分为两个步骤。

【讨论】:

这是一个测试项目。如果可能的话,它可以出售。主要是为我工作的一家金融公司服务。程序 A 是允许将 C++ 代码添加到有限扩展的第三方程序。确实有太多的数据要写入硬盘。程序 A 有大约 100 个函数,主要调用另一个位置的服务器(即存储在异地的数据)。我要求提供 API 功能,但他们不愿意让我直接访问。因此,程序 A 与服务器 C 对话...以复制所有数据,不幸的是无法正常工作。 附言。获取其中一些数据具有关键的时间意义。所以我的解决方案必须既容易实现(即不想使用消息传递,因为这将需要编写每个函数两次 - 一次用于消息 - 另一个用于解码端以了解应该调用哪个函数)和快速。 @DaClan 我对进程间通信不是很熟悉。那么使用 TCP 连接呢?你可以把你的程序做成服务器,把程序A中的东西做成客户端。

以上是关于通过内存共享 C++ 对象的主要内容,如果未能解决你的问题,请参考以下文章

c++内存示例08从本共享

C++ 中具有共享内存的远程代理

仅使用本机 C++ 操作为多个进程创建共享内存? [关闭]

与linux和windows c++兼容的共享内存库[关闭]

C++ 无法在我的 Windows 应用程序中重写共享内存。它分配新的内存

共享内存段与共享内存对象