MPI_Bcast一个动态的2D阵列

fau*_*pin 9 c mpi

我试图将带有bcast的动态二维数组传递给所有排名.我有以下代码.

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

int main(int argc, char **argv)
{   
    float **array;
    int rank,size,i,j;

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

    if(rank==0)
    {
        array = (float **)malloc(10*sizeof(float));
        for(i=0;i<10;i++)
            array[i] = (float *)malloc(10*sizeof(float));

        for(i=0;i<10;i++)
        for(j=0;j<10;j++)
            array[i][j]=i+j;
    }
    MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
    MPI_Finalize();
}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,我无法理解我得到分段错误.谁知道问题是什么?

Jon*_*rsi 27

这里有三个问题 - 一个涉及分配,一个涉及分配的位置,一个涉及MPI如何工作,而其他答案都没有完全触及所有这些问题.

第一个也是最严重的问题是事情的分配.正如@davidb正确指出的那样,因为它只是在任务零上分配内存,所以其他任务没有内存来接收广播.

至于C中的2d分配,您的代码几乎完全正确.在这段代码中:

     array = (float **)malloc(10*sizeof(float));
     for(i=0;i<10;i++)
         array[i] = (float *)malloc(10*sizeof(float));
Run Code Online (Sandbox Code Playgroud)

唯一真正的问题是第一个malloc应该是10个浮点指针,而不是浮点数:

     array = (float **)malloc(10*sizeof(float *));
     for(i=0;i<10;i++)
         array[i] = (float *)malloc(10*sizeof(float));
Run Code Online (Sandbox Code Playgroud)

@eznme指出了这一点.第一种方式可能实际上取决于您正在编译/链接的内存模型等,并且几乎肯定会在32位操作系统/机器上工作 - 但仅仅因为它的工作并不总是意味着它是正确的:)

现在,最后一个问题是你在C中声明了一个非常好的2d数组,但这不是MPI所期望的.当你打这个电话

MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
Run Code Online (Sandbox Code Playgroud)

你告诉MPI发送指向的100 个连续浮点数array.您注意到库例程无法知道数组是指向2d或3d或12d数组的开头的指针,还是各个维度的指针; 它不知道它是否必须遵循指针,如果确实如此,它将不知道要跟随多少.

因此,您希望向100个连续的浮点数发送浮点指针 - 并且以正常的C方式分配伪多维数组(*),您不一定拥有它.您不一定知道第二行距离此布局中的第一行有多远 - 甚至在哪个方向.所以你真正想做的是这样的事情:

int malloc2dfloat(float ***array, int n, int m) {

    /* allocate the n*m contiguous items */
    float *p = (float *)malloc(n*m*sizeof(float));
    if (!p) return -1;

    /* allocate the row pointers into the memory */
    (*array) = (float **)malloc(n*sizeof(float*));
    if (!(*array)) {
       free(p);
       return -1;
    }

    /* set up the pointers into the contiguous memory */
    for (int i=0; i<n; i++) 
       (*array)[i] = &(p[i*m]);

    return 0;
}

int free2dfloat(float ***array) {
    /* free the memory - the first element of the array is at the start */
    free(&((*array)[0][0]));

    /* free the pointers into the memory */
    free(*array);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这样,只有这样,才能保证内存是连续的.那你可以做

float **array;
/* ... */
malloc2dfloat(&array, 10, 10);
if (rank == 0) {
    for(i=0;i<10;i++)
         for(j=0;j<10;j++)
              array[i][j]=i+j;
}
MPI_Bcast(&(array[0][0]), 10*10, MPI_FLOAT, 0, MPI_COMM_WORLD);
Run Code Online (Sandbox Code Playgroud)

请注意,对于任意数据排列,您仍然可以Bcast通过定义MPI数据类型来描述2d数组如何在内存中实际布局; 但这更简单,更接近你真正想要的东西.

(*)这里真正的问题是C和C派生的语言没有真正的多维数组作为第一类对象 - 这对于系统编程语言来说很好,但在进行科学编程时却无可救药.


小智 7

array应该是100,而不是10,因为你每次分配每行10辆彩车.JackN的答案有代码来做到这一点.

但是,在除0级以外的任何进程上,指向数组的指针都将是null.您需要在所有进程上初始化数组,然后在根上填充数组.

你可以将malloc代码移出if (rank ==0)块,它应该如你所愿.