2011-12-01 97 views
3

我有一个2D双精度数组,并行操作由几个进程。每个进程操纵数组的一部分,并且在每次迭代结束时,我需要确保所有进程都具有二维数组的相同副本。MPI广播二维数组

假设一个大小为10 * 10和2个进程(或处理器)的数组。过程1(P1)操纵2D行的前5行(总共5 * 10 = 50个元素),P2操纵最后5行(总共50个元素)。在每次迭代结束时,我需要P1(它自己的前5行+ P2的最后5行)。 P2应该有(P1的前5行+它是OWN的最后5行)。我希望这个场景很清楚。

我想使用下面给出的代码进行广播。但我的程序不断退出,出现此错误:“应用程序终止与退出字符串:挂断(信号1)”。

我已经使用了一个连续的2D内存分配器,正如这里指出的那样:Jonathan的MPI_Bcast a dynamic 2d array。但我仍然遇到同样的错误。

有人可以帮我吗?

我的代码:

double **grid, **oldgrid; 
int gridsize; // size of grid 
int rank, size; // rank of current process and no. of processes 
int rowsforeachprocess, offset; // to keep track of rows that need to be handled by each process 

/* allocation, MPI_Init, and lots of other stuff */ 

rowsforeachprocess = ceil((float)gridsize/size); 
offset = rank*rowsforeachprocess; 

/* Each process is handling "rowsforeachprocess" #rows. 
* Lots of work done here 
* Now I need to broadcast these rows to all other processes. 
*/ 

for(i=0; i<gridsize; i++){ 
    MPI_Bcast(&(oldgrid[i]), gridsize-2, MPI_DOUBLE, (i/rowsforeachprocess), MPI_COMM_WORLD); 
} 

第2部分:上面的代码是使用一维分解拉普拉斯方程并行求解器的一部分,我不想使用一个主-worker模式。如果我使用Master-Worker模型,我的代码会更容易吗?

回答

2

这里引起崩溃的问题是一个2d数组指针问题&(oldgrid [i])是一个指向双打的指针,而不是指向双打的指针,它指向指针排我的阵列,而不是你阵列的第一行。你想要MPI_Bcast(&(oldgrid[i][0]),..MPI_Bcast(oldgrid[i],...

还有另一种方法来做到这一点,它只使用一个昂贵的集体通信器,而不是每行一个;如果您需要每个人都拥有整个阵列的副本,则可以使用MPI_Allgather将数据收集在一起并分发给每个人;或者在进程不具有相同行数的一般情况下,MPI_Allgatherv。相反,在循环播放的,这看起来有点像:

{ 
    int *counts = malloc(size*sizeof(int)); 
    int *displs = malloc(size*sizeof(int)); 
    for (int i=0; i<size; i++) { 
     counts[i] = rowsforeachprocess*gridsize; 
     displs[i] = i*rowsforeachprocess*gridsize; 
    } 
    counts[size-1] = (gridsize-(size-1)*rowsforeachprocess)*gridsize; 

    MPI_Allgatherv(oldgrid[offset], mynumrows*gridsize, MPI_DOUBLE, 
        oldgrid[0],  counts, displs, MPI_DOUBLE, MPI_COMM_WORLD); 
    free(counts); 
    free(displs); 
} 

其中计数通过各任务的项目数,并displs是位移。

但最后,你确定每个进程都必须有整个数组的副本吗?如果你只是计算一个拉普拉斯算子,你可能只需要相邻的行,而不是整个数组。

这看起来像:

int main(int argc, char**argv) { 
double **oldgrid; 
const int gridsize=10; // size of grid 
int rank, size;  // rank of current process and no. of processes 
int rowsforeachprocess; // to keep track of rows that need to be handled by each process 
int offset, mynumrows; 
MPI_Status status; 

MPI_Init(&argc, &argv); 
MPI_Comm_size(MPI_COMM_WORLD, &size); 
MPI_Comm_rank(MPI_COMM_WORLD, &rank); 

rowsforeachprocess = (int)ceil((float)gridsize/size); 
offset = rank*rowsforeachprocess; 
mynumrows = rowsforeachprocess; 
if (rank == size-1) 
    mynumrows = gridsize-offset; 

rowsforeachprocess = (int)ceil((float)gridsize/size); 
offset = rank*rowsforeachprocess; 
mynumrows = rowsforeachprocess; 
if (rank == size-1) 
    mynumrows = gridsize-offset; 

malloc2ddouble(&oldgrid, mynumrows+2, gridsize); 

for (int i=0; i<mynumrows+2; i++) 
    for (int j=0; j<gridsize; j++) 
     oldgrid[i][j] = rank; 

/* exchange row data with neighbours */ 
int highneigh = rank+1; 
if (rank == size-1) highneigh = 0; 

int lowneigh = rank-1; 
if (rank == 0) lowneigh = size-1; 

/* send data to high neibhour and receive from low */ 

MPI_Sendrecv(oldgrid[mynumrows], gridsize, MPI_DOUBLE, highneigh, 1, 
      oldgrid[0],   gridsize, MPI_DOUBLE, lowneigh, 1, 
      MPI_COMM_WORLD, &status); 

/* send data to low neibhour and receive from high */ 

MPI_Sendrecv(oldgrid[1],   gridsize, MPI_DOUBLE, lowneigh, 1, 
      oldgrid[mynumrows+1], gridsize, MPI_DOUBLE, highneigh, 1, 
      MPI_COMM_WORLD, &status); 


for (int proc=0; proc<size; proc++) { 
    if (rank == proc) { 
     printf("Rank %d:\n", proc); 
     for (int i=0; i<mynumrows+2; i++) { 
      for (int j=0; j<gridsize; j++) { 
       printf("%f ", oldgrid[i][j]); 
      } 
      printf("\n"); 
     } 
     printf("\n"); 
    } 
    MPI_Barrier(MPI_COMM_WORLD); 
} 
+0

我只是想出了这个问题,在MPI_Bcast自己的指针地址。 :) 但谢谢你指向我的Allgather命令。另外,你所说的每个进程只需要来自其邻近进程的一行就很有意义!我会试试看。 – Neo