1

我有一个主应用程序,它产生一个本身产生两个奴隶的工人。从应用程序将其输出写入标准输出。我的想法是将标准输出绑定到工作应用程序中的不同流,以便能够将从属的输出存储在一个变量中并将其发送给处理输出的主控。但是,从属设备的标准输出没有正确重定向,仍然出现在控制台上。工作应用程序中的缓冲区保持为空。我是否遗漏了某些东西,或者这在我做这件事的方式上是不可能的?如果是这样,任何有关如何以不同方式处理此问题的建议将不胜感激。我在 Gentoo 上使用 Open MPI 1.6.5,这是我的应用程序的源代码:

大师.cpp

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

using namespace std;

int main(int argc, char *argv[])
{
    char appExe[] = "worker";
    char *appArg[] = {NULL};
    int maxProcs = 1;
    int myRank; 
    MPI_Comm childComm;
    int spawnError;

    // Initialize
    MPI_Init(&argc, &argv);

    // Rank 
    MPI_Comm_rank(MPI_COMM_WORLD, &myRank);

    // Spawn application    
    MPI_Comm_spawn(appExe, appArg, maxProcs, MPI_INFO_NULL, myRank, MPI_COMM_SELF, &childComm, &spawnError);

    // Receive length of message from worker
    int len;
    MPI_Recv(&len, 1, MPI_INT, 0, MPI_ANY_TAG, childComm, MPI_STATUS_IGNORE);
    // Receive actual message from worker
    char *buf = new char[len];
    MPI_Recv(buf, len, MPI_CHAR, 0, MPI_ANY_TAG, childComm, MPI_STATUS_IGNORE);
    cout << "master: Got the following from worker: " << buf << endl;

    // Finalize
    MPI_Finalize();

    return 0;
}

工人.cpp

#include "mpi.h"
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

int main(int argc, char *argv[])
{
    char appExe[] = "slave";
    char *appArg[] = {NULL};
    int maxProcs = 2;
    int myRank, parentRank; 
    MPI_Comm childComm, parentComm;
    int spawnError[maxProcs];

    // Initialize
    MPI_Init(&argc, &argv);

    // Rank
    MPI_Comm_rank(MPI_COMM_WORLD, &myRank);

    // Get parent
    MPI_Comm_get_parent(&parentComm);

    // Bind stdout to new_buffer
    stringstream new_buffer;
    streambuf *old_buffer = cout.rdbuf(new_buffer.rdbuf());  

    // Spawn application    
    MPI_Comm_spawn(appExe, appArg, maxProcs, MPI_INFO_NULL, myRank, MPI_COMM_SELF, &childComm, spawnError);

    // Enter barrier
    MPI_Barrier(childComm);

    // Reset stdout to old_buffer
    cout.rdbuf(old_buffer);

    // Make a string
    string tmp = new_buffer.str();
    // Make a character array from string
    const char* cstr = tmp.c_str();
    cout << "worker: Got the following from slaves: " << cstr << endl;

    // Send length of message to master   
    int len = sizeof(cstr);
    MPI_Send(&len, 1, MPI_INT, 0, 0, parentComm);
    // Send actual message
    MPI_Send(&cstr, len, MPI_CHAR, 0, 0, parentComm);

    // Finalize
    MPI_Finalize();

    return 0;
}

从属.cpp

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

using namespace std;

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

    // Initialize
    MPI_Init(&argc, &argv);

    // Get parent
    MPI_Comm_get_parent(&parent);

    // Say hello
    cout << "slave: Hi there!" << endl;

    // Enter barrier
    if (parent != MPI_COMM_NULL)
        MPI_Barrier(parent);

    // Finalize
    MPI_Finalize();

    return 0;
}
4

2 回答 2

1

MPI 中的作业生成发生在同一个“宇宙”中,通常由用于启动初始 MPI 作业的同一应用程序启动器执行。在 Open MPI 中,这将是orterunmpiexec并且mpirun都是指向 的符号链接orterun)。I/O 重定向由 ORTE(Open MPI 运行时环境,MPI 库的一部分)执行,它将每个 MPI 进程的标准输出发送到orterun,然后混合所有内容并将其显示到控制台输出或保存如果输出重定向到位,则发送到文件。除非衍生作业专门将其输出写入文件,否则父作业无法拦截该输出。

在父作业和衍生作业之间进行通信的另一种(也是唯一的)符合 MPI 的方式是使用 MPI 消息传递。您可以实现自己的 C++ 输入和输出流类,这些类使用 MPI 消息通过交互器传输数据。

于 2013-08-10T14:46:58.607 回答
0

一般来说,在分布式应用程序中使用 stdout/stderr 进行重要输出并不是正确的方法。很难强制执行有用的排序,这有时会导致行混乱在一起。将数据读/写到可以通过 NFS 或某些脚本移动的文件通常要有效得多。然后你知道排序是正确的。

于 2013-08-08T13:43:37.967 回答