这里涉及到三个问题——一个涉及分配,一个涉及分配的位置,一个涉及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中声明了一个完全良好的2D数组,但这不是MPI所期望的。当您进行这个调用时:
MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
您要告诉MPI发送由array
指向的100个连续浮点数。您可能会注意到,库例程无法知道array
是2d、3d还是12d数组的起始指针,也不知道每个维度的大小;它不知道是否要跟随指针,如果要跟随指针,也不知道要跟随多少个。
因此,您想要发送一个指向100个连续浮点数的指针,但在C语言中分配伪多维数组的普通方式(*)中,并不一定满足这个条件。您可能不确定第二行在这种布局中与第一行相距多远,甚至不确定方向。因此,您真正想要做的是像这样:
int malloc2dfloat(float ***array, int n, int m) {
float *p = (float *)malloc(n*m*sizeof(float));
if (!p) return -1;
(*array) = (float **)malloc(n*sizeof(float*));
if (!(*array)) {
free(p);
return -1;
}
for (int i=0; i<n; i++)
(*array)[i] = &(p[i*m]);
return 0;
}
int free2dfloat(float ***array) {
free(&((*array)[0][0]));
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);
请注意,对于任意数据排列,您仍可以通过定义描述2d数组在内存中实际布局的MPI数据类型来执行Bcast
。但这种方法更简单,更接近您实际想要的。
(*) 这里的真正问题是,C和C派生语言没有真正的多维数组作为一流对象 - 对于系统编程语言来说这很好,但在科学编程时会非常烦人。