2014-09-02 169 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