阻止执行,直到通过MPI_Comm_spawn调用的子项完成

时间:2013-07-30 15:09:16

标签: c++ mpi

我正在修改现有的应用程序,我想在其中生成动态创建的bash脚本。我创建了一个简单的包装程序,它将bash脚本的名称作为参数。在包装器中,脚本由MPI_Comm_spawn生成。在之后,包装器调用MPI_Finalize,它在脚本完成之前执行:

#include "mpi.h"
#include <stdlib.h>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    char *script = argv[1];
    int maxProcs = 2, myRank;
    MPI_Comm childComm;
    int spawnError[maxProcs];

    // Initialize
    argv[1] = NULL;
    MPI_Init(&argc, &argv);

    // Rank of parent process
    MPI_Comm_rank(MPI_COMM_WORLD, &myRank);    

    // Spawn application    
    MPI_Comm_spawn(script, MPI_ARGV_NULL, maxProcs, MPI_INFO_NULL, myRank, MPI_COMM_SELF, &childComm, spawnError);

    // Finalize
    MPI_Finalize();

    return EXIT_SUCCESS;
}

如果我插入

    sleep(10);

之前

    MPI_Finalize ();
一切正常。现在我的问题是,在bash脚本完成之前是否可以阻止包装器中的执行?此外,获得脚本的返回值会很好。 不幸的是,不能为脚本创建另一个包装器,它与父包装器通信并通过系统调用执行bash脚本,因为我需要从脚本中访问MPI环境变量。我希望,我已经说清楚了。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:3)

如果您可以控制bash脚本的内容,即如果你可以在spawn之前放入一些内容,那么一个非常粗略的选择就是编写一个包含单个MPI_Barrier行的特殊MPI程序:

#include <mpi.h>

int main (int argc, char **argv)
{
   MPI_Comm parent;

   MPI_Init(&argc, &argv);

   // Obtain an intercommunicator to the parent MPI job
   MPI_Comm_get_parent(&parent);

   // Check if this process is a spawned one and if so enter the barrier
   if (parent != MPI_COMM_NULL)
      MPI_Barrier(parent);

   MPI_Finalize();

   return 0;
}

将程序编译为与主MPI程序使用的相同的MPI分布的任何其他MPI程序,并将其称为waiter。然后在bash脚本的最开头设置一个EXIT陷阱:

#!/bin/bash
trap "/path/to/waiter $*" EXIT
...
# End of the script file

同时修改主程序:

// Spawn application    
MPI_Comm_spawn(script, MPI_ARGV_NULL, maxProcs, MPI_INFO_NULL, myRank, MPI_COMM_SELF, &childComm, spawnError);

// Wait for the waiters to enter the barrier
MPI_Barrier(childComm);

// Finalize
MPI_Finalize();

在{1}}中调用waiter非常重要,因为它可以接收bash脚本将接收的所有命令行参数,因为一些旧的MPI实现会向生成的可执行文件附加额外的参数。为了向它提供父连接信息。符合MPI-2的实现通常通过环境提供此信息,以支持waiter $*

这种方式非常简单:MPI_Init(NULL, NULL)命令指示shell在脚本退出时执行trapwaiter本身只是与父MPI工作建立一个互通,并等待障碍。一旦所有衍生的脚本完成,所有这些脚本都会作为退出陷阱的一部分启动服务员进程,屏障将被解除。

如果你不能修改脚本,那么只需创建一个调用实际脚本的包装脚本并将服务器放在包装器中。

测试并使用Open MPI和Intel MPI。

答案 1 :(得分:1)

没有办法让我知道MPI_COMM_SPAWN阻止,这里通常的解决方案是在产生者和产生者之间有一个MPI_BARRIER。不幸的是,你没有遵循MPI应用程序产生另一个MPI应用程序的通常模型。相反,你只是运行一堆脚本。要获得所需的结果,您可能必须使用MPI之外的其他内容,或者想办法为远程bash脚本编写MPI包装器。

答案 2 :(得分:0)

为什么你没有使用fork加exec实际执行脚本的子MPI应用程序。脚本名称可以作为参数传递给使用MPI_Comm_spawn或MPI_Comm_spawn_multiple创建的子项。然后,这些孩子通过处理SIGCHLD等待脚本完成等待,或者如果有错误则等待脚本完成。脚本完成后,您可以在父项和子MPI进程之间输入一个屏障,然后通过调用MPI_Finalize来终止。

儿童计划与Hristo Iliev提出的计划类似:

#include <mpi.h>

int main (int argc, char **argv){
   MPI_Comm parent;
   MPI_Init(&argc, &argv);
   MPI_Comm_get_parent(&parent);

   pid = fork();  
   if (pid < 0) { // error while forking
       exit (-1);
   } else if (pid == 0) { // child
       execvp(<nome of the script parsed from parameters in argv or other means>);
   } else { // parent
       wait(<pid of the child>); // there are non-blocking alternatives if needed
   }

   if (parent != MPI_COMM_NULL){
      MPI_Barrier(parent);
   }

   MPI_Finalize();

   return 0;
}

父程序只发出spawn(如果有一个脚本名称)或spawn_multiple(如果每个衍生的MPI进程都有不同的脚本名称),然后与衍生的子进程间通信器形成障碍这是MPI生成操作的输出参数。

相关问题