Здесь есть три проблемы - одна связана с распределением, одна связана с тем, где он распределен, а другая - с тем, как работает 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 указателей , а не float:
array = (float **)malloc(10*sizeof(float *));
for(i=0;i<10;i++)
array[i] = (float *)malloc(10*sizeof(float));
Thisбыло отмечено @eznme.Первый способ может фактически работать в зависимости от того, с какой моделью памяти вы компилируете / связываете и т. Д., И почти наверняка будет работать на 32-битных ОС / машинах - но только потому, что он работает, не всегда означает, что он прав:)
Теперь, последняя проблема в том, что вы объявили совершенно хороший 2d массив в C, но это не то, чего ожидает MPI.Когда вы делаете этот вызов
MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
, вы говорите MPI отправить 100 непрерывных чисел с плавающей точкой, на которые указывает array
.Вы замечаете, что у библиотечной подпрограммы нет способа узнать, является ли массив указателем на начало массива 2d, 3d или 12d, или каковы отдельные измерения;он не знает, должен ли он следовать указателям, и если он это сделал, он не будет знать, сколько следует следовать.
Таким образом, вы хотите отправить указатель с плавающей точкой на 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;
}
Таким образом, и только так, вы гарантируете, что память непрерывна.Затем вы можете сделать
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 не имеют реальных массивов multi-d в качестве объектов первого класса - чтоотлично подходит для языка системного программирования, но неумолимо раздражает при научном программировании.