Thomas
Thomas

Reputation: 43

How to send/receive an array of structure to/from other processor?

I'm trying to store structures into an array and use MPI to send it to other processor(rank 0) but when I receive it at rank 0, I can't seem to read the data as it doesn't output it when I want to print. Let's say there are only 2 processors. I'm very new in C.

This my code:

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

    int rank, size;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Status stat;

    struct student {
        unsigned char id;
        unsigned char age;
    };

    struct student *ptrA;
    struct student std;
    struct student oneRow[10];
    struct student rowsPerProcess[30];
    struct student allRows[50];


    if(rank != 0) {

        for (int y = 0; y < 2; y++) {
            for (int x = 0; x < 2; x++) {

                if (x == 0) {
                    std.id = 105;
                    std.age = 18;
                } else {
                    std.id = 100;
                    std.age = 20;
                }

                oneRow[x] = std;
            }
            memcpy( rowsPerProcess + 2, oneRow, sizeof(oneRow) );
        }

        MPI_Send(rowsPerProcess, 4, MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD);

    } else {
        MPI_Recv(allRows, 20, MPI_UNSIGNED_CHAR, 1, 0, MPI_COMM_WORLD, &stat);
        printf("first student's ID: %c\n", allRows[0].id);
        printf("first student's age: %c\n", allRows[0].age);

        printf("second student's ID: %c\n", allRows[1].id);
        printf("second student's age: %c\n", allRows[1].age);

    }

    MPI_Finalize();
    return 0;

}

This is my output, I can print the strings but not the data (eg: allRows[0].id):

first student's ID:
first student's age: 
second student's ID: 
second student's age:

Upvotes: 0

Views: 546

Answers (2)

j23
j23

Reputation: 3530

In the sample code provided by you, you don't need to use memcpy at all to achieve the desired objective. You can directly send the structure elements from the object oneRow itself. The outer loop is also unnecessary. So the below code will make the send and receive work. Also, you are sending 4 characters and receiving 20.

if(rank != 0) {
            for (int x = 0; x < 2; x++) {
                if (x == 0) {
                    std.id = 'a';
                    std.age = 'b';
                } else {
                    std.id = 'c';
                    std.age = 'd';
                }
                   oneRow[x] = std;
        }
        MPI_Send(oneRow, 4, MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD);
       } else {
        MPI_Recv(oneRow, 4, MPI_UNSIGNED_CHAR, 1, 0, MPI_COMM_WORLD, &stat);
        printf("first student's ID: %c\n", oneRow[0].id);
        printf("first student's age: %c\n", oneRow[0].age);
        printf("second student's ID: %c\n", oneRow[1].id);
        printf("second student's age: %c\n", oneRow[1].age);

    }

To send structures in MPI, the best way to do is to create derived data type using MPI_Type_create_struct. If the two characters are aligned in a contiguous memory area (i.e., like in the above example.), you don't need a derived datatype.

For a struct:

   typedef  struct student_t {
        int  id;
        int age;
    }student;

You can create a derived data type in MPI using the following:

/* create a type for struct student */
const int nitems=2; // Number of Elements in struct
int blocklengths[2] = {1,1};
MPI_Datatype types[2] = {MPI_INT, MPI_INT}; // data type of struct elements
MPI_Datatype mpi_std_type; //derived type name
MPI_Aint     offsets[2]; // offset of the variable

offsets[0] = offsetof(student, age);
offsets[1] = offsetof(student, id);

MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_std_type);
MPI_Type_commit(&mpi_std_type);

You can then create the array of struct as student send[2] and send it using MPI_Send() as MPI_Send(&send, 2, mpi_std_type, dest, tag, MPI_COMM_WORLD); using the derived data type (mpi_std_type) as the type of the data. Similarly also in the receiver side.

So the resulting program will look like:

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

   typedef  struct student_t {
        int  id;
        int age;
    }student;

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

    const int tag = 13;
    int size, rank;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    /* create a type for struct student */
    const int nitems=2;
    int          blocklengths[2] = {1,1};
    MPI_Datatype types[2] = {MPI_INT, MPI_INT};
    MPI_Datatype mpi_std_type;
    MPI_Aint     offsets[2];

    offsets[0] = offsetof(student, age);
    offsets[1] = offsetof(student, id);

    MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_std_type);
    MPI_Type_commit(&mpi_std_type);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        student send_struct[2];
        send_struct[0].id = 1;
        send_struct[0].age = 2;

        send_struct[1].id = 3;
        send_struct[1].age = 4;
        const int dest = 1;
        MPI_Send(&send_struct,   2, mpi_std_type, dest, tag, MPI_COMM_WORLD);

        printf("Rank %d: sent structure student\n", rank);
    }
    if (rank == 1) {
        MPI_Status status;
        const int src=0;

        student recv_struct[2];

        MPI_Recv(&recv_struct,   2, mpi_std_type, src, tag, MPI_COMM_WORLD, &status);
        printf("Rank %d: Received: id = %d age = %d \n", rank,
                 recv_struct[0].id, recv_struct[0].age);

        printf("Rank %d: Received: id = %d age = %d \n", rank,
                 recv_struct[1].id, recv_struct[1].age);
    }

    MPI_Type_free(&mpi_std_type);
    MPI_Finalize();

    return 0;
}

Upvotes: 1

Amila Senadheera
Amila Senadheera

Reputation: 13225

You can get to log what you need by following steps,

1) You need to change count to be the same amount. So replace 20 with 4.

2) Replace %c to %d to see the integer values. Otherwise you will see useless character symbols.

Upvotes: 1

Related Questions