MPI如何从从节点接收动态数组?

时间:2016-03-14 12:29:42

标签: c++ parallel-processing mpi

我是MPI的新手。我想将三个int发送到三个从节点以创建动态数组,每个数组将被发送回主节点。根据这个post,我修改了代码,它接近正确的答案。但是当我在接收器代码中从slave#3(m == 3)接收到数组时,我得到了断点。提前谢谢!

我的代码如下:

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

int main(int argc, char** argv)
{
    int firstBreakPt, lateralBreakPt;
    //int reMatNum1, reMatNum2;
    int tmpN;

    int breakPt[3][2]={{3,5},{6,9},{4,7}};

    int myid, numprocs;
    MPI_Status status;

//  double *reMat1;
//  double *reMat2;


    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

    tmpN = 15;

    if (myid==0)
    {
        // send three parameters to slaves;
        for (int i=1;i<numprocs;i++)
        {
            MPI_Send(&tmpN,1,MPI_INT,i,0,MPI_COMM_WORLD);

            firstBreakPt = breakPt[i-1][0];
            lateralBreakPt = breakPt[i-1][1];           

            //std::cout<<i<<" "<<breakPt[i-1][0] <<" "<<breakPt[i-1][1]<<std::endl;

            MPI_Send(&firstBreakPt,1,MPI_INT,i,1,MPI_COMM_WORLD);
            MPI_Send(&lateralBreakPt,1,MPI_INT,i,2,MPI_COMM_WORLD);
        }

        // receive arrays from slaves;
        for (int m =1; m<numprocs; m++)
        {
            MPI_Probe(m, 3, MPI_COMM_WORLD, &status);

            int nElems3, nElems4;
            MPI_Get_elements(&status, MPI_DOUBLE, &nElems3);

            // Allocate buffer of appropriate size
            double *result3 = new double[nElems3];
            MPI_Recv(result3,nElems3,MPI_DOUBLE,m,3,MPI_COMM_WORLD,&status);

            std::cout<<"Tag is 3, ID is "<<m<<std::endl;
            for (int ii=0;ii<nElems3;ii++)
            {
                std::cout<<result3[ii]<<std::endl;
            }

            MPI_Probe(m, 4, MPI_COMM_WORLD, &status);
            MPI_Get_elements(&status, MPI_DOUBLE, &nElems4);

            // Allocate buffer of appropriate size
            double *result4 = new double[nElems4];
            MPI_Recv(result4,nElems4,MPI_DOUBLE,m,4,MPI_COMM_WORLD,&status);

            std::cout<<"Tag is 4, ID is "<<m<<std::endl;
            for (int ii=0;ii<nElems4;ii++)
            {
                std::cout<<result4[ii]<<std::endl;
            }
        }
    }
    else
    {
        // receive three paramters from master;
        MPI_Recv(&tmpN,1,MPI_INT,0,0,MPI_COMM_WORLD,&status);

        MPI_Recv(&firstBreakPt,1,MPI_INT,0,1,MPI_COMM_WORLD,&status);
        MPI_Recv(&lateralBreakPt,1,MPI_INT,0,2,MPI_COMM_WORLD,&status);

        // width
        int width1 = (rand() % (tmpN-firstBreakPt+1))+ firstBreakPt;
        int width2 = (rand() % (tmpN-lateralBreakPt+1))+ lateralBreakPt;

        // create dynamic arrays
        double *reMat1 = new double[width1*width1];
        double *reMat2 = new double[width2*width2];

        for (int n=0;n<width1; n++)
        {
            for (int j=0;j<width1; j++)
            {
                reMat1[n*width1+j]=(double)rand()/RAND_MAX + (double)rand()/(RAND_MAX*RAND_MAX); 
                //a[i*Width+j]=1.00;
            }
        }

        for (int k=0;k<width2; k++)
        {
            for (int h=0;h<width2; h++)
            {
                reMat2[k*width2+h]=(double)rand()/RAND_MAX + (double)rand()/(RAND_MAX*RAND_MAX); 
                //a[i*Width+j]=1.00;
            }
        }

        // send it back to master
        MPI_Send(reMat1,width1*width1,MPI_DOUBLE,0,3,MPI_COMM_WORLD);
        MPI_Send(reMat2,width2*width2,MPI_DOUBLE,0,4,MPI_COMM_WORLD);
    }

    MPI_Finalize();

    std::cin.get();

    return 0;
}

P.S。这段代码是正确的答案。

2 个答案:

答案 0 :(得分:2)

使用集体MPI操作,正如Zulan所说。例如,您的代码所做的第一件事就是根向所有从属发送相同的值,即广播,即getPreferredSize()。然后,根向每个从设备发送一个不同的值,即散射值,即MPI_Bcast()

最后一个操作是从属进程发送到根可变大小的数据,其中存在MPI_Scatter()函数。但是,要使用此功能,您需要:

  1. 按root分配传入缓冲区(代码的第一个if分支中MPI_Gatherv()malloc()没有reMat1),因此,root需要知道他们的算,
  2. 告诉reMat2 将从每个奴隶接收多少元素以及放置它们的位置。
  3. 通过所谓的并行前缀可以轻松解决此问题,请查看MPI_Gatherv()MPI_Scan()

答案 1 :(得分:0)

在这里创建随机宽度

    int width1 = (rand() % (tmpN-firstBreakPt+1))+ firstBreakPt;
    int width2 = (rand() % (tmpN-lateralBreakPt+1))+ lateralBreakPt;

您稍后用于将数据发送回流程0

    MPI_Send(reMat1,width1*width1,MPI_DOUBLE,0,3,MPI_COMM_WORLD);

但它预计会有不同数量的

    MPI_Recv(reMat1,firstBreakPt*tmpN*firstBreakPt*tmpN,MPI_DOUBLE,m,3,MPI_COMM_WORLD,&status);

导致问题。它不知道每个从属进程生成的大小,因此您必须以与向其发送大小相同的方式发回它们。