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 массивов в качестве объектов первого класса - что прекрасно для системного языка программирования, но безвозвратно раздражает при выполнении научного программирования .


массив должен быть 100, а не 10.

array = (float **)malloc(100*sizeof(float)); 

вы, вероятно, хотите изменить первый 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*))