【问题标题】:Linux, share a buffer with another program in fork()Linux,在 fork() 中与另一个程序共享一个缓冲区
【发布时间】:2013-04-28 20:28:47
【问题描述】:

我有一个客户端/服务器模型,其中每个客户端都可以向服务器发送任务 - 这称为任务请求。

这是我所追求的简单分布式计算库的基础。

"换句话说,如果一些普通应用程序处理一个独立元素的数组,那么在数据并行模型中,每个处理器都被分配处理数组的一部分。为了支持数据并行计算,核心库应该将任务分成多个部分,将任务数据传输到特定 CPU 的本地内存,在该 CPU 上运行任务,将结果传输回调用者,并提供从调用者请求一些全局数据的能力。 "

  • TaskBinary(std::vector uint8_t) 和 Payload(std::vector uint8_t)。
  • 二进制文件只是一个已编译的任务/应用程序。
  • Payload 是序列化为 uint8_t 的可选数据。

这么简单:

class CGridTask
{

    public:
        ...

        bool        Run             ();    

    private:
        std::vector<uint8_t>        m_vBinary;
        std::vector<uint8_t>        m_vPayload;
        uint32_t                    m_uiUniqueId;

        ...
}

伪图显示了它是如何“工作”的:

[CLIENT1]---[SEND TASK with PAYLOAD: integer value = 10]-->[SERVER]

[SERVER]-->[RUN TASK with PAYLOAD]

[TASK, start]

[TASK, calculate...]
[TASK, calculate...]
[TASK, calculate...]
[TASK, integer value = 10 + some new value]

[TASK, return]

[SERVER]-->[SEND TASK to CLIENT1]

好的,所以当服务器调用时:

pGridTask->Run();

这是应该发生的事情:

bool CGridTask::Run()
{
    // Dump the binary to a temporary file
    Dump(m_vBinary);

    // Chmod +x
    system("chmod +x " + strTempopraryBinaryName);

    // Run the binary and pass m_vPayload
    ...how can i do this?...

    // Return true if binary executed
    return true;
}

这里唯一的问题是与执行的二进制文件共享 m_vPayload... 我该怎么做?

非常感谢您对此的任何意见!

【问题讨论】:

  • 我建议阅读 advancedlinuxprogramming.com,因为您可以在不共享 共享内存 缓冲区的情况下设计应用程序(如果您真的想为缓冲区共享一些内存,您还需要其他一些同步机制,所以共享内存是不够的......)。

标签: c++ c linux posix shared-memory


【解决方案1】:

假设您想修改内存以便“主”进程可以看到它,您需要设置一个共享内存区域或内存映射文件。当新进程写入时,作为进程一部分分配的任何内存都将被复制,因此不会“共享”。

【讨论】:

  • @PeeS 在放置包含指针(例如向量)的对象时要小心:地址仅在创建它们的进程的内存空间中才有意义。你可能想看看boost.interprocess
  • 是的,mmap 应该可以工作,但是您需要使用shm_open() 创建一个命名的共享内存区域,以便您可以将某些内容作为文件传递给mmap
  • 你仍然需要一些同步(在各个进程之间),所以仅仅共享一些缓冲内存是不够的......
  • 无论采用哪种方式解决多线程或进程之间的数据共享都是如此。
【解决方案2】:

作为其他解决方案的替代方案,根据您的子进程的结构,您还可以通过管道与子进程通信(通常的pipe/fork/dup2/exec 模式)。

当然性能比共享内存差,但整个架构更灵活,你的各种程序耦合度会低得多:从孩子的角度来看,它从stdin获取数据并输出结果到stdout,这使得它可以很容易地在其他上下文中重用(并且它也使得在任务服务器的上下文中重用“普通”交互式程序变得非常容易,而无需先调整它们)。

【讨论】:

  • 我绝对同意这个提议。
  • 谢谢,我在这个模型中使用了这种方法。
【解决方案3】:

我不会推荐它.. 但这样你可以“分享一切”

不要将fork()我们clone()与以下标志一起使用:CLONE_VM

CLONE_VM(自 Linux 2.0 起)

如果设置了CLONE_VM,则调用进程和子进程运行在同一个内存空间。特别是,内存写入由 调用进程或由子进程在 其他过程。此外,执行的任何内存映射或取消映射 子进程或调用进程使用 mmap(2) 或 munmap(2) 也会影响 另一个进程。

如果没有设置 CLONE_VM,子进程在执行 clone() 时在调用进程的内存空间的单独副本中运行。 由其中一个执行的内存写入或文件映射/取消映射 进程不会影响其他进程,就像 fork(2) 一样。

更多信息http://linux.die.net/man/2/clone

但我相信你会遇到这个问题..动态分配的内存会泄漏..和co.

真正的解决方案是为有效负载设置一个 mmap..

【讨论】:

  • 不要使用clone;这是一个非常低级的系统调用,本质上是为线程库实现者(那些能够掌握futex)保留的。
  • @BasileStarynkevitch 你可以用clone 做一些非常有趣的事情,但正如我所说,我不推荐它.. 为多个进程使用一个内存,只会产生比它解决的问题更多的问题。
【解决方案4】:

除了其他答案,您还可以考虑使用MPI消息传递接口标准,它有多种实现,包括Open MPI

当然 MPI 不是共享内存模型,但它似乎与您的“发送数据部分”的高级软件架构很接近。

MPI 如此普遍,以至于一些高端的铁供应商(即百万欧元的超级计算机)提供了他们自己的硬件辅助 MPI 实施。

您也可以使用 Posix 共享内存,即shm_open(3) 和朋友。见shm_overview(7)。然后你可能想与 Posix 信号量同步。先看sem_overview(7)

并且mmap(2)也可以用来共享内存(带有MAP_SHARED标志)。

共享内存是不够的。你需要一些同步工具(告诉共享数据“准备好使用”......)。

也许你可以考虑 Pthreads。阅读好的Pthread tutorial(最近的C++2011标准也提供了线程)。

阅读Advanced Linux Programming,了解Linux 下的众多IPC 可能性。作为Siyam suggested,通常的pipeforkdup2exec(以及用于输入和输出多路复用的poll(2))值得考虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    相关资源
    最近更新 更多