2015-10-03 3 views
0

Я пытаюсь отправить структуру, которая имеет один из членов как динамический массив, но этот массив, кажется, не отправляется должным образом. Любое предложение о том, как это сделать?Создать тип MPI для структуры, содержащей динамический массив

Это то, что у меня есть:

struct bar 
{ 
    int a; 
    int b; 
    int* c; 
}; 

void defineMPIType(MPI_Datatype* newType, int cLen, struct bar* msg) 
{ 
    int blockLengths[3] = {1, 1, cLen}; 
    MPI_Datatype types[3] = {MPI_INT, MPI_INT, MPI_INT}; 
    MPI_Aint offsets[3]; 

    MPI_Aint addrB, addrC; 
    MPI_Address(&(msg->b), &addrB); 
    MPI_Address(msg->c, &addrC); 

    offsets[0] = offsetof(struct bar, a); 
    offsets[1] = offsetof(struct bar, b); 
    offsets[2] = addrC - addrB; 

    MPI_Type_create_struct(3, blockLengths, offsets, types, newType); 
    MPI_Type_commit(newType); 
} 

void main(int argc, char* argv[]) 
{ 
    MPI_Init(&argc, &argv); 
    int rank, p; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &p); 

    int cLen = argv[0];  
    MPI_Datatype MPI_BAR_TYPE; 

    struct bar* msg = malloc(sizeof(*msg)); 
    msg->c = malloc(sizeof(int) * cLen); 
    defineMPIType(&MPI_BAR_TYPE, cLen, msg); 

    if (rank == 0) 
    { 
     msg->a = 1; 
     msg->b = 2; 
     for (int i = 0; i < cLen; ++i) 
      msg->c[i] = i; 
     MPI_Send(msg, 1, MPI_BAR_TYPE, 1, 111, MPI_COMM_WORLD); 
    } 
    else 
    { 
     MPI_Status stat;   
     MPI_Recv(msg, 1, MPI_BAR_TYPE, 0, 111, MPI_COMM_WORLD, &stat);  
    } 

    printf("Rank %d has c = [", rank); 
    for (int i = 0; i < cLen; ++i) 
     printf("%d, ", msg->c[i]); 
    printf("]\n"); 

    free(msg); 
    MPI_Type_free(&MPI_BAR_TYPE); 
    MPI_Finalize(); 
} 

Пользователи a и b был отправлен правильно, но c не сделал.

+1

Вам необходимо захватить c * с типом MPI, когда он известен. – Jeff

ответ

2

Есть несколько вопросов, в вашем коде, даже не обращая внимания на вопрос самого типа:

  • Первый из них, что вы выделили память для c массива только на процесс # 0, то вы (пробовали чтобы) отправить эти данные в процесс №1. Но процесс № 1 не выделял никакой памяти для хранения сообщения. Поэтому, даже если способ отправки был правильным, код не удался.
  • Имена, начинающиеся с MPI_, зарезервированы для библиотеки MPI, поэтому вы не можете использовать их по своему усмотрению. Вы должны найти другое имя для своего MPI_BAR_TYPE.
  • Эта строка несколько озадачивает меня: int cLen = argv[0]; Я предполагаю, что вы хотите прочитать из командной строки размер массива для выделения, и в этом случае, возможно, это должно прочитать что-то вроде int clen = atoi(argv[1]); (забыв о тесте на достоверность этого, который должен был бы должным образом обрабатываться ...)
  • Вы только проверяете, является ли процесс ранга № 0 или нет, что означает, что если по какой-то причине вы запустили 3 процесса, процесс ранга №2 будет ждать навсегда для сообщения из процесса ранг № 0, который никогда не появится.
  • И, наконец, сам массив: в вашем коде есть большая путаница между указателем c и данными, на которые указывает c. В вашей структуре встроен указатель, но не указана память. Таким образом, вы не можете сопоставить в структуру MPI соответствующие данные ... Самая очевидная причина заключается в том, что от одного вызова до следующего (или от одного процесса к другому) нет гарантии, что смещение от адреса структуры и адрес данных, на которые указывает c, будет идентичным (и действительно, почти гарантировано, что он будет другим). Поэтому вы не можете надежно их сопоставить.

Что вам нужно сделать для решения вашей проблемы, поэтому только передать ваши 2 целых a и b на одном дыхании (возможно создание структуры MPI для передачи массивов из них в случае необходимости). Затем вы переведете память, указанную c, которую вы бы выделили заранее.

Ваш код может стать, например:

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

struct bar 
{ 
    int a; 
    int b; 
    int* c; 
}; 

void defineMPIType(MPI_Datatype* newType) { 
    struct bar tmp[2]; 
    MPI_Aint extent = &tmp[1] - &tmp[0]; 

    MPI_Type_create_resized(MPI_2INT, 0, extent, newType); 
    MPI_Type_commit(newType); 
} 

int main(int argc, char* argv[]) { 
    MPI_Init(&argc, &argv); 
    int rank, p; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &p); 

    int cLen = atoi(argv[1]);  
    MPI_Datatype Bar_type; 
    defineMPIType(&Bar_type); 

    struct bar msg; 
    msg.c = (int*) malloc(sizeof(int) * cLen); 
    if (rank == 0) { 
     msg.a = 1; 
     msg.b = 2; 
     for (int i = 0; i < cLen; ++i) { 
      msg.c[i] = i; 
     } 
     MPI_Send(&msg, 1, Bar_type, 1, 111, MPI_COMM_WORLD); 
     MPI_Send(msg.c, cLen, MPI_INT, 1, 222, MPI_COMM_WORLD); 
    } 
    else if (rank == 1) { 
     MPI_Recv(&msg, 1, Bar_type, 0, 111, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
     MPI_Recv(msg.c, cLen, MPI_INT, 0, 222, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
    } 

    printf("Rank %d has a = %d, b = %d, c = [", rank, msg.a, msg.b); 
    for (int i = 0; i < cLen - 1; ++i) { 
     printf("%d, ", msg.c[i]); 
    } 
    printf("%d]\n", msg.c[cLen - 1]); 

    free(msg.c); 
    MPI_Type_free(&Bar_type); 
    MPI_Finalize(); 

    return 0; 
} 

Что дает:

$ mpirun -n 2 ./a.out 3 
Rank 0 has a = 1, b = 2, c = [0, 1, 2] 
Rank 1 has a = 1, b = 2, c = [0, 1, 2] 

Счастливый MPI кодирования.

+0

Спасибо за ответ! Да, мой пример был несколько испорчен, потому что я попытался оставить некоторые нерелевантные вещи из реального кода (например, cLen передается из другого места, а не из командной строки). В любом случае, о вашем подходе, да, я должен был сделать два MPI_Sends раньше, но я стараюсь этого не делать. Я работаю над проектом, где мы не можем взять на себя порядок доставки сообщений.Кроме того, я бы любил НЕ иметь совпадение a и b с правильным c, если бы я отправлял несколько сообщений. –

+0

Я обновил код с возможностью отправки в одном сообщении, но кажется, что последний элемент массива 'c' является единственным, который не отправляется должным образом. –

+0

Это не сработает, поскольку, как я сказал вы не можете предположить конкретное размещение памяти для памяти, на которое указывает 'c' относительно самого указателя' c' ... Так что это просто не сработает! Если вы не можете иметь статическое распределение памяти в своей структуре, вы будете необходимо передать структуру и данные в два отдельных сообщения (если вы не вручную упакуете свои данные в буфер, возможно, с помощью «MPI_Pack», но я бы не рекомендовал этого). – Gilles

Смежные вопросы