2017-07-14 47 views
0

我需要还原节点从其他节点获取元素列表(存储在向量中)的副本。我定义了我自己的减少功能,但它不起作用。该程序终止/崩溃。传递并推入MPI_Reduce中的向量

这是代码:

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

using namespace std; 

void pushTheElem(vector<int>* in, vector<int>* inout, int *len, MPI_Datatype *datatype) 
{ 
    vector<int>::iterator it; 
    for (it = in->begin(); it < in->end(); it++) 
    { 
     inout->push_back(*it); 
    } 
} 

int main(int argc, char **argv) 
{ 
    int numOfProc, procID; 
    vector<int> vect, finalVect; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numOfProc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &procID); 

    MPI_Op myOp; 
    MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp); 

    for (int i = 0; i < 5; i++) 
    { 
     vect.push_back(procID); 
    } 

    MPI_Reduce(&vect, &finalVect, 5, MPI_INT, myOp, 0, MPI_COMM_WORLD); 

    if (procID == 0) 
    { 
     vector<int>::iterator it; 
     cout << "Final vector elements: " << endl; 

     for (it = finalVect.begin(); it < finalVect.end(); it++) 
      cout << *it << endl; 
    } 

    MPI_Finalize(); 
    return 0; 
} 
+0

请提供有关崩溃的一些细节。至少应该有某种异常发生......程序的输出是什么? –

+0

这就是我得到的:工作中止:[等级]消息。没有调用finalize,退出[0]进程。 [1]终止。 ----错误分析----- testMPI.exe过早结束并可能崩溃。退出代码0xc0000005。 – Jack

+0

当我用2个进程运行程序时,我知道了。 – Jack

回答

3

看来你要收集所有进程的所有元素。这是不是还原,它是一个收集操作。的减少结合了相同长度的多个阵列此特定长度的数组:

MPI_Reduce

这不是的情况下,组合两个数组时产生长度等于输入数组的总和的阵列。使用MPI,您不能简单地使用指针来操作,就像您在缩减操作中所做的那样。由于进程具有单独的地址空间,因此无法向MPI发送指针。 MPI接口确实使用指针,但只使用包含已知类型和已知大小的数据区域。

您可以通过MPI_Gather轻松完成您的任务。

MPI_Gather

// vect.size() must be the same on every process, otherwise use MPI_Gatherv 
// finalVect is only needed on the root. 
if (procID == 0) finalVect.resize(numOfProc * vect.size()); 
MPI_Gather(vect.data(), 5, MPI_INT, finalVect.data(), 5, MPI_INT, 0, MPI_COMM_WORLD); 
+0

非常感谢,这正是我所需要的。 – Jack

1

我不认为你可以通过使用MPI这样的载体。 MPI执行什么操作需要第一个指针,并将其解释为INT类型的数据块,并且定义了长度。请考虑矢量如何实现。向量本身就是一个小的控制结构,指向堆上的某个数组。所以传递vector *不是提供指向数据的指针,而是指向这个控制结构,当你的程序尝试使用它作为向量时,这会导致未定义的行为。

您需要使用MPI对原始数据进行操作。试试这个(没有测试过,因为我手头没有MPI):

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

using namespace std; 

void pushTheElem(int* in, int* inout, int *len, MPI_Datatype *datatype) 
{ 
    for(inti=0;i<*len;++i){ 
     inout[i]=in[i]; 
    } 
} 

int main(int argc, char **argv) 
{ 
    int numOfProc, procID; 
    vector<int> vect, finalVect; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numOfProc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &procID); 

    MPI_Op myOp; 
    MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp); 

    for (int i = 0; i < 5; i++) 
    { 
     vect.push_back(procID); 
    } 
    finalVect.resize(vect.size()); 
    MPI_Reduce(vect.data(), finalVect.data(), 5, MPI_INT, myOp, 0, MPI_COMM_WORLD); 

    if (procID == 0) 
    { 
     vector<int>::iterator it; 
     cout << "Final vector elements: " << endl; 

     for (it = finalVect.begin(); it < finalVect.end(); it++) 
      cout << *it << endl; 
    } 

    MPI_Finalize(); 
    return 0; 
} 
+0

非常感谢,现在我明白它是如何工作的。该代码不会产生任何错误。唯一的是finalVect将始终只有从上次处理过程中获得的元素。 pushTheElem中的循环会覆盖finalVect中已有的任何内容。 – Jack

+0

@Jack预期的行为是什么?如果使用2个MPI任务运行,您能指定finalVect中的期望吗? –

+0

我基本上希望输出包含从两个进程收集的元素。 @Zulan向我澄清说,我应该使用的是MPI_Gather,它给了我正确的输出。谢谢。 – Jack