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*))
Другие вопросы по тегам