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, в настоящий момент вы выделяете память только для задачи ноль, поэтому у других задач нет памяти для приема трансляции.
Что касается двумерного размещения в 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-битных ОС / машинах - но только потому, что он работает, не всегда означает, что он прав:)
Теперь последняя проблема в том, что вы объявили очень хороший 2d массив в C, но MPI этого не ожидает. Когда вы делаете этот звонок
MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD);
Вы говорите MPI отправить 100 смежных чисел, на которые указывает array
, Вы замечаете, что у библиотечной подпрограммы нет способа узнать, является ли массив указателем на начало 2d или 3d или 12d массива, или каковы отдельные измерения; он не знает, должен ли он следовать указателям, и если бы он это делал, он не знал бы, сколько им следовать.
Таким образом, вы хотите отправить указатель с плавающей точкой на 100 непрерывных чисел с плавающей точкой - и при обычном способе распределения псевдо-многомерных массивов (*) у вас это не обязательно есть. Вы не обязательно знаете, как далеко 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, не имеют реальных многомерных массивов в качестве объектов первого класса - что хорошо для языка системного программирования, но необратимо раздражает при выполнении научного программирования.
Массив должен быть 100, а не 10.
array = (float **)malloc(100*sizeof(float));
Вы, вероятно, хотите изменить первый malloc на
malloc(10*sizeof(void*))
потому что массив хранит указатели и хранит числа с плавающей точкой вместо int:
array[i][j]=1.0;
Если вы хотите выделить массив с 10*10, ваш код:
array = (float **)malloc(10*sizeof(float))
должно быть
array = (float **)malloc(10*sizeof(float*))