这里有三个问题 - 一个涉及分配,一个涉及分配位置,一个涉及 MPI 的工作原理,其他答案都没有涉及所有这些。
第一个也是最严重的问题是分配的地方。正如@davidb 正确指出的那样,就目前而言,您仅在任务零上分配内存,因此其他任务没有用于接收广播的内存。
至于 C 中的二维分配,您的代码几乎完全正确。在这段代码中:
array = (float **)malloc(10*sizeof(float));
for(i=0;i<10;i++)
array[i] = (float *)malloc(10*sizeof(float));
唯一真正的问题是第一个 malloc 应该是 10 个浮点 指针,而不是浮点数:
array = (float **)malloc(10*sizeof(float *));
for(i=0;i<10;i++)
array[i] = (float *)malloc(10*sizeof(float));
@eznme 指出了这一点。第一种方法实际上可能取决于您正在编译/链接的内存模型等,并且几乎肯定会在 32 位操作系统/机器上工作 - 但仅仅因为它工作并不总是意味着它是正确的 :)
现在,最后一个问题是您已经在 C 中声明了一个非常好的二维数组,但这不是 MPI 所期望的。当您拨打此电话时
MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
您告诉 MPI 发送 array 指向的 100 个 连续 浮点数。您注意到库例程无法知道 array 是否是指向 2d 或 3d 或 12d array 开头的指针,或者各个维度是什么;它不知道它是否必须遵循指针,如果这样做了,它也不知道要遵循多少。
所以你想发送一个浮点指针到 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;
}
这样,也只有这样,才能保证内存是连续的。然后就可以了
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);
请注意,对于任意排列的数据,您仍然可以通过定义一个 MPI 数据类型来执行Bcast,该数据类型描述了二维数组是如何实际在内存中布局的;但这更简单,更接近您可能真正想要的。
(*) 这里真正的问题是 C 和 C 派生的语言没有真正的多维数组作为第一类对象——这对于系统编程语言来说很好,但在进行科学编程时却是不可挽回的恼人。