【问题标题】:Can I pass an object to another process just passing its' pointer to a shared memory?我可以将一个对象传递给另一个进程,只需将其指针传递给共享内存吗?
【发布时间】:2011-05-20 03:43:35
【问题描述】:

我有一个非常复杂的类(它里面有 unordered_map 等),我想与我的两个进程共享它的一个对象。我可以简单地将一个指向它的指针从一个进程传递给另一个进程吗?我想,不,但希望听到“是的!”。

如果“否”,我会很高兴看到任何链接如何应对这种情况。 对于所有进程,我只需要这个对象的一个​​实例,因为它非常大,并且所有进程都可以在只读状态下工作。

【问题讨论】:

  • @如果你可以控制这些进程,为什么不把它们变成线程呢?共享内存比。似乎更明智,因为他们都将了解其内部数据结构(您共享对象)
  • 是的,我想我会走这条路。我问了这个问题,以确保我没有简单的 IPC 解决方案。

标签: c++ ipc shared-memory


【解决方案1】:

不,进程不(自然)共享内存。如果 boost 是一个选项,那么您可以查看Boost.Interprocess 以轻松共享内存。

【讨论】:

    【解决方案2】:

    不,指针对其他进程没有意义。操作系统为其他进程创建单独的地址空间;默认情况下,他们不知道其他进程正在运行,甚至不知道这样的事情是可能的。

    【讨论】:

    • 这是我准备好的答案,但希望能有一些技巧:(
    【解决方案3】:

    这里的诀窍是内存必须在两个进程中以相同的方式映射。如果你的映射共享内存可以这样安排,它会起作用,但我敢打赌这会非常困难。

    还有其他几种可能性。第一个是使用数组;数组索引在两个进程中起作用。

    您还可以使用placement new 来确保您在共享内存中的已知位置分配对象,并使用这些偏移量。

    【讨论】:

      【解决方案4】:

      如果你在 linux 上,你可以使用共享内存来存储进程之间的公共数据。对于一般情况,请查看 boost IPC 库。

      但是来自一个进程的指针不能在另一个进程中使用(如果访问IO,或者一些特殊设备,可以使用它的地址)

      【讨论】:

        【解决方案5】:

        如果您使用 Qt4,则有 QSharedMemory 或者您可以使用套接字和自定义序列化协议。

        【讨论】:

          【解决方案6】:

          您当然可以使用 IPC 来实现这一点,并且在很多情况下,多进程比多线程进程更有意义(至少有一个进程是基于您无法进行大量修改的遗留代码构建的,它们最好用不同的语言编写,您需要最大限度地减少一个进程中出现故障的机会,从而影响其他进程的稳定性等。)在与 POSIX 兼容的环境中,您会这样做

          int descriptor = shm_open("/unique_name_here", O_RDWR | O_CREAT, 0777);
          
          if (descriptor < 0) {
              /* handle error */
          } else {
          
              ftruncate(descriptor, sizeof(Object));
              void *ptr = mmap(NULL, sizeof(Object), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, descriptor, 0);
          
              if (!ptr || ptr == MAP_FAILED)
                  /* handle error */ ;
          
              Object *obj = new (ptr) Object(arguments);
          }
          

          在一个过程中,然后

          int descriptor = shm_open("/the_same_name_here", O_RDWR | O_CREAT, 0777);
          
          if (descriptor < 0) {
              /* handle error */
          } else {
          
            Object *obj = (Object *) mmap(NULL, sizeof(Object), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, descriptor, 0);
          
            if (!obj || obj == MAP_FAILED)
                /* handle error */ ;
          }
          

          在另一个。还有更多选项,完成后我没有显示清理代码,因此您仍然应该阅读 shm_open() 和 mmap() 联机帮助页,但这应该可以帮助您入门。需要记住的几点:

          • /All/ 对象使用的内存需要共享。例如,如果 Object 包含指向其他对象的指针或引用,或动态分配的成员(包括容器、std::string 等),则必须使用placement new 来创建所有内容(或至少所有需要与其他进程共享)在共享内存 blob 中。您不需要为每个对象创建一个新的 shm_open(),但是您必须(在创建过程中)跟踪它们的大小和偏移量,这在非平凡的情况下很容易出错,如果有的话,绝对会令人毛骨悚然花哨的自动分配类型,例如 STL 容器。

          • 如果任何进程在对象被共享后会对其进行修改,则您需要提供单独的同步机制。这并不比你在多线程程序中做的更糟糕,但你必须考虑一下。

          • 如果“客户端”进程不需要修改共享对象,您应该使用 O_RDONLY 而不是 O_RDWR 打开它们的句柄,并在没有 PROT_WRITE 权限标志的情况下调用 mmap()。如果客户端进程可能进行不需要与其他进程共享的本地修改,请使用 MAP_PRIVATE 而不是 MAP_SHARED 调用 mmap()。这将大大减少所需的同步量以及搞砸的风险。

          • 如果这些进程将在多用户系统上运行和/或共享数据可能是敏感的和/或这是一个高可用性应用程序,那么您将需要比所示更复杂的访问控制更多。共享内存是安全漏洞的常见来源。

          【讨论】:

          • 如果我用placement new 运算符构造一个对象,它会自动用相同的运算符构造它的成员吗?
          • 非指针成员当然会在分配给父对象的空间内构造。如果您的类构造函数或其他方法使用 new 为其他对象分配空间,则该内存将/不/位于共享 blob 内。如第一个项目符号所述,这可能是复杂性和错误的主要来源。如果您的共享对象过于复杂而无法手动避免这种行为,您可以考虑定义一个自定义的 new 运算符,该运算符在设置特定全局标志时在 blob 内部进行分配。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-17
          • 2016-07-20
          • 2018-09-16
          • 1970-01-01
          • 2015-09-15
          • 2015-05-09
          相关资源
          最近更新 更多