MPI Bcast динамический 2d массив
Я пытаюсь передать динамический 2D-массив с 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();
}
по какой-то причине я не могу понять, что я получаю ошибку сегментации. Кто что знает в чем проблема?
5 ответов
на array
должно быть 100, а не 10, так как вы назначаете 10 поплавков в каждой строке. Ответ Джека имеет код для этого.
однако в любом процессе, отличном от ранга 0, указатель на массив будет null
.
Вам нужно инициализировать массив во всех процессах, а затем заполнить массив в корне.
вы можете просто переместить код malloc из if (rank ==0)
блок и он должен работать, как вы ожидаете.
здесь есть три вопроса - один, связанный с распределениями, один, связанный с тем, где он выделяется, и один, связанный с тем, как работает MPI, и ни один из других ответов не касается всех из них.
первый и самый серьезный вопрос, где выделены вещи. Как правильно указал @davidb, поскольку вы выделяете память только на нулевой задаче, поэтому у других задач нет памяти, в которой можно получить трансляцию.
как для 2d распределений в C вообще, ваш код почти точно. В этом блоке кода:
array = (float **)malloc(10*sizeof(float));
for(i=0;i<10;i++)
array[i] = (float *)malloc(10*sizeof(float));
единственная реальная проблема заключается в том, что первый malloc должен быть 10 float указатели, не плывет:
array = (float **)malloc(10*sizeof(float *));
for(i=0;i<10;i++)
array[i] = (float *)malloc(10*sizeof(float));
это было указано @eznme. Первый способ может фактически работать в зависимости от того, с какой моделью памяти вы компилируете / связываете и т. д., и почти наверняка будет работать на 32-битных ОС / машинах, но только потому, что он работает, не всегда означает, что это правильно:)
Итак, последняя проблема в том, что вы объявили совершенно хороший 2D-массив в C, но это не то, что ожидает MPI. Когда вы делаете этот звонок
MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
вы говорите MPI отправить 100 прилежащей поплавки, на которые указывает array
. Вы замечаете, что библиотечная процедура не может знать, является ли array указателем на начало 2d или 3d или 12D массива или каковы отдельные размеры; он не знает, должен ли он следовать указателям, и если бы он это сделал, он не знал бы, сколько следовать.
таким образом, вы хотите отправить указатель float на 100 смежных поплавков - и в обычном способе c выделения псевдо-многомерных массивов (*) у вас это не обязательно есть. Вы не обязательно знаете, как далеко 2-я строка от 1-й строки в этом макете - или даже в каком направлении. Так что вы действительно хотите сделать что-то вроде этого:
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;
}
таким образом, и только таким образом, вы гарантируете, что память непрерывна. Тогда вы можете do
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);
обратите внимание, что для произвольного расположения данных вы все равно можете сделать Bcast
определив тип данных MPI, который описал, как 2d-массив на самом деле выложил в памяти, но это проще и ближе к тому, что скорее всего, вы на самом деле хотите.
(*) реальная проблема здесь в том, что C и C-производные языки не имеют реальных мульти-D массивов в качестве объектов первого класса - что прекрасно для системного языка программирования, но безвозвратно раздражает при выполнении научного программирования .
вы, вероятно, хотите изменить первый malloc для
malloc(10*sizeof(void*))
потому что массив хранит указатели и хранит поплавки вместо ints:
array[i][j]=1.0;
Если вы хотите выделить массив 10*10, код:
array = (float **)malloc(10*sizeof(float))
должно быть
array = (float **)malloc(10*sizeof(float*))