MPI_Scatter в C с использованием 2d-массива [дубликат]

Если все остальное не удается, перекомпилируйте.

Недавно я смог избавиться от нерешенной внешней ошибки в Visual Studio 2012, просто перекомпилировав нарушивший файл. Когда я перестроил, ошибка исчезла.

Это обычно происходит, когда две (или более) библиотеки имеют циклическую зависимость. Библиотека A пытается использовать символы в B.lib и библиотеке B пытается использовать символы из A.lib. Ничего не существует для начала. Когда вы пытаетесь скомпилировать A, шаг ссылки завершится неудачно, потому что он не может найти B.lib. A.lib будет сгенерирован, но не будет dll. Затем вы компилируете B, который будет успешным и сгенерирует B.lib. Повторная компиляция A теперь будет работать, потому что теперь найден B.lib.

6
задан rvw 17 November 2013 в 15:32
поделиться

1 ответ

Я думаю, что вы принципиально неправильно поняли, что делает операция рассеяния и как MPI ожидает выделения и использования памяти.

MPI_Scatter берет исходный массив и разбивается на части, отправляя уникальную часть каждому члену MPI-коммуникатора. В вашем примере вам понадобится ваша матрица для распределения смежных элементов p*p в линейной памяти, которые будут отправлять значения p в каждый процесс. Ваша исходная «матрица» представляет собой массив указателей. Нет гарантии, что строки последовательно расположены в памяти, а MPI_Scatter не знает, как перемещаться по массиву указателей, которые вы передали. В результате, вызов просто читается за пределами первой строки, которую вы передали по косвенности указателя на матрицу, обрабатывая все, что следует в памяти как данные. Вот почему вы получаете значения мусора в процессах, которые получают данные после первой строки.

Все процедуры копирования данных MPI предполагают, что исходная и целевая память являются «плоскими» линейными массивами. Многомерные массивы C должны храниться в главном порядке row не в массивах указателей, как вы это делали здесь. Дешевый неприятный взлома вашего примера для иллюстрации правильного разворота, будет выглядеть следующим образом:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

int *createMatrix (int nrows, int ncols) {
    int *matrix;
    int h, i, j;

    if (( matrix = malloc(nrows*ncols*sizeof(int))) == NULL) {
        printf("Malloc error");
        exit(1);
    }

    for (h=0; h<nrows*ncols; h++) {
        matrix[h] = h+1;
    }

    return matrix;
}

void printArray (int *row, int nElements) {
    int i;
    for (i=0; i<nElements; i++) {
        printf("%d ", row[i]);
    }
    printf("\n");
}

int main (int argc, char **argv) {

    if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
        perror("Error initializing MPI");
        exit(1);
    }

    int p, id;
    MPI_Comm_size(MPI_COMM_WORLD, &p); // Get number of processes
    MPI_Comm_rank(MPI_COMM_WORLD, &id); // Get own ID

    int *matrix;

    if (id == 0) {
        matrix = createMatrix(p, p); // Master process creates matrix
        printf("Initial matrix:\n");
        printArray(matrix, p*p);
    }

    int *procRow = malloc(sizeof(int) * p); // received row will contain p integers
    if (procRow == NULL) {
        perror("Error in malloc 3");
        exit(1);
    }

    if (MPI_Scatter(matrix, p, MPI_INT, // send one row, which contains p integers
                procRow, p, MPI_INT, // receive one row, which contains p integers
                0, MPI_COMM_WORLD) != MPI_SUCCESS) {

        perror("Scatter error");
        exit(1);
    }

    printf("Process %d received elements: ", id);
    printArray(procRow, p);

    MPI_Finalize();

    return 0;
}

, который делает это:

$ mpicc -o scatter scatter.c 
$ mpiexec -np 4 scatter
Initial matrix:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
Process 0 received elements: 1 2 3 4 
Process 1 received elements: 5 6 7 8 
Process 2 received elements: 9 10 11 12 
Process 3 received elements: 13 14 15 16 

т.е. при передаче данных, хранящихся в линейной памяти, он работает. Эквивалентный основной массив строк будет статически распределен следующим образом:

int matrix[4][4] = { {  1,  2,  3,  4 }, 
                     {  5,  6,  7,  8 },
                     {  9, 10, 11, 12 },
                     { 13, 14, 15, 16 } };

Обратите внимание на разницу между статически распределенным двумерным массивом и массивом указателей, которые ваш код выделяет динамически , Они вовсе не одно и то же, хотя они внешне внешне похожи.

12
ответ дан talonmies 26 August 2018 в 15:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: