2014-09-02 122 views
1

我是MPI的新手。我写了一个简单的代码来显示使用多个进程的矩阵。说如果我有一个8x8的矩阵,并用4个进程启动MPI程序,则会在第一个进程中打印第一个2行,由第二个线程打印的第二个2行将通过平均分割来打印。MPI中的动态内存分配

#define S 8 

MPI_Status status; 

int main(int argc, char *argv[]) 
{ 
int numtasks, taskid; 
int i, j, k = 0; 

MPI_Init(&argc, &argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &taskid); 
MPI_Comm_size(MPI_COMM_WORLD, &numtasks); 

int rows, offset, remainPart, orginalRows, height, width; 
int **a; 
// int a[S][S]; 

if(taskid == 0) 
{ 
    cout<<taskid<<endl; 
    height = width = S; 

    a = (int **)malloc(height*sizeof(int *)); 
    for(i=0; i<height; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 

    for(i=0; i<S; i++) 
     for(j=0; j<S; j++) 
      a[i][j] = ++k; 

    rows = S/numtasks; 
    offset = rows; 
    remainPart = S%numtasks; 

    cout<<"Num Rows : "<<rows<<endl; 

    for(i=1; i<numtasks; i++) 
     if(remainPart > 0) 
     { 
      orginalRows = rows; 
      rows++; 
      remainPart--; 

      MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

      offset += rows; 
      rows = orginalRows; 
     } 
     else 
     { 
      MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD); 
      MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

      offset += rows; 
     } 

     //Processing 
     rows = S/numtasks; 
     for(i=0; i<rows; i++) 
     { 
      for(j=0; j<width; j++) 
       cout<<a[i][j]<<"\t"; 
      cout<<endl; 
     } 
}else 
{ 
    cout<<taskid<<endl; 

    MPI_Recv(&offset, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    MPI_Recv(&rows, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    MPI_Recv(&width, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    a = (int **)malloc(rows*sizeof(int *)); 
    for(i=0; i<rows; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 
    MPI_Recv(&a, rows*width, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 
    cout<<"Offset : "<<offset<<"\nRows : "<<rows<<"\nWidth : "<<width<<endl; 

    for(i=0; i<rows; i++) 
    { 
     for(j=0; j<width; j++) 
      cout<<a[i][j]<<"\t"; 
     cout<<endl; 
    } 
} 

getch(); 
MPI_Finalize(); 

return 0; 
} 

这是我的完整代码,我在这里已经分配的内存中动态的“一”,而打印[i] [j],else部分下,我得到的运行时错误。如果我将动态内存分配更改为静态,例如将int ** a更改为int a [N] [N]并删除

a = (int **)malloc(rows*sizeof(int)); 
    for(i=0; i<rows; i++) 
     a[i] = (int *)malloc(width*sizeof(int)); 

它可以很好地工作。

+0

....会发生什么当您尝试动态内存分配?你有什么问题?我在文字中看不到一个问号(或者我是盲人?)。 – gurka 2014-09-02 17:10:12

+1

Stack Overflow询问同样的问题还有无数其他问题。为什么不简单地使用搜索功能? – 2014-09-10 08:24:25

+1

您需要分配一维数组内存。看起来你的阵列是不连续的。 – Jeff 2015-04-19 23:47:58

回答

7

至少有两种方式来动态分配二维数组。

第一个是@HRoid之一:每行一次分配一个。查看here获取方案。

第二个是@Claris建议的,它会确保数据在内存中是连续的。这是许多MPI操作所需要的...它也是像FFTW(二维快速傅里叶变换)或Lapack(线性代数的稠密矩阵)这样的库所需要的。你的程序可能无法在

MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD); 

如果S>1,这一计划将尝试发送都行N°offset结束之后的项目......这可能引发分段错误或不确定的行为。

您可以分配您的阵列this way

a = malloc(rows * sizeof(int *)); 
if(a==NULL){fprintf(stderr,"out of memory...i will fail\n");} 
int *t = malloc(rows * width * sizeof(int)); 
if(t==NULL){fprintf(stderr,"out of memory...i will fail\n");} 
for(i = 0; i < rows; ++i) 
    a[i] = &t[i * width]; 

当心:mallocdoes not initialize memory to 0

看来你想要在许多过程中传播2D数组。看看MPI_Scatterv()here。也请看this question

如果您想了解更多关于2D阵列和MPI的信息,请看here

您可能会找到一个MPI_Scatterv here的基本示例。

我将#define S 8更改为#define SQUARE_SIZE 42。提供描述性名称总是更好。

这里是使用MPI_Scatterv()的工作代码!

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

using namespace std; 

#define SQUARE_SIZE 42 

MPI_Status status; 

int main(int argc, char *argv[]) 
{ 
    int numtasks, taskid; 
    int i, j, k = 0; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid); 
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks); 

    int rows, offset, remainPart, orginalRows, height, width; 
    int **a; 

    height = width = SQUARE_SIZE; 

    //on rank 0, let's build a big mat of int 
    if(taskid == 0){ 
     a=new int*[height]; 
     int *t =new int[height * width]; 
     for(i = 0; i < height; ++i) 
      a[i] = &t[i * width]; 
     for(i=0; i<height; i++) 
      for(j=0; j<width; j++) 
       a[i][j] = ++k; 
    } 

    //for everyone, lets compute numbers of rows, numbers of int and displacements for everyone. Only 0 will use these arrays, but it's a practical way to get `rows` 
    int nbrows[numtasks]; 
    int sendcounts[numtasks]; 
    int displs[numtasks]; 
    displs[0]=0; 
    for(i=0;i<numtasks;i++){ 
     nbrows[i]=height/numtasks; 
     if(i<height%numtasks){ 
      nbrows[i]=nbrows[i]+1; 
     } 
     sendcounts[i]=nbrows[i]*width; 
     if(i>0){ 
      displs[i]=displs[i-1]+sendcounts[i-1]; 
     } 
    } 
    rows=nbrows[taskid]; 

    //scattering operation. 
    //The case of the root is particular, since the communication is not to be done...Hence, the flag MPI_IN_PLACE is used. 
    if(taskid==0){ 
     MPI_Scatterv(&a[0][0],sendcounts,displs,MPI_INT,MPI_IN_PLACE,0,MPI_INT,0,MPI_COMM_WORLD); 
    }else{ 
     //allocation of memory for the piece of mat on the other nodes. 
     a=new int*[rows]; 
     int *t =new int[rows * width]; 
     for(i = 0; i < rows; ++i) 
      a[i] = &t[i * width]; 

     MPI_Scatterv(NULL,sendcounts,displs,MPI_INT,&a[0][0],rows*width,MPI_INT,0,MPI_COMM_WORLD); 
    } 
    //printing, one proc at a time 
    if(taskid>0){ 
     MPI_Status status; 
     MPI_Recv(NULL,0,MPI_INT,taskid-1,0,MPI_COMM_WORLD,&status); 
    } 
    cout<<"rank"<< taskid<<" Rows : "<<rows<<" Width : "<<width<<endl; 

    for(i=0; i<rows; i++) 
    { 
     for(j=0; j<width; j++) 
      cout<<a[i][j]<<"\t"; 
     cout<<endl; 
    } 
    if(taskid<numtasks-1){ 
     MPI_Send(NULL,0,MPI_INT,taskid+1,0,MPI_COMM_WORLD); 
    } 

    //freeing the memory ! 

    delete[] a[0]; 
    delete[] a; 

    MPI_Finalize(); 

    return 0; 
} 

编译:mpiCC main.cpp -o main

运行:mpiexec -np 3 main

+0

我已经删除了我的答案,因为你的更相关。 – HRold 2014-09-02 19:26:43

+0

@francis,我已经按照你说的方式分配了数据,但我仍然得到了同样的错误。请你再帮我一次。 现在我要试试MPI_Scatterv。谢谢。 – suraj1291993 2014-09-09 14:14:00

1

此代码看起来非常可疑。

a = (int **)malloc(rows*sizeof(int)); 
for(i=0; i<rows; i++) 
    a[i] = (int *)malloc(width*sizeof(int)); 
MPI_Recv(&a, rows*width, MPI_INT, 0, 1, MPI_COMM_WORLD, &status); 

您创建一个int **数组并正确分配,但不会传递单个指针。 MPI_Recv期望int *作为参数,对吗?

请注意,当您执行int [] []时,分配的内存将是连续的。当你做malloc时,你应该期望非连续的内存块。

一个简单的解决方案可能只是做a = (int**) malloc (big),然后索引这个大的内存分配。

+0

数组分配不正确,第一级malloc必须使用'sizeof(int *)'而不是'sizeof(int)'。 – HRold 2014-09-02 17:36:22

+0

@HRold,我改变了你说的,谢谢...仍然没有工作。请你再帮我一次。 – suraj1291993 2014-09-09 14:09:13

+0

@ suraj1291993是的,你可以给出'MPI_Recv()'函数的原型吗? – HRold 2014-09-11 20:56:55