Управление структурами через MPI_Send и MPI_recv в C

Я все еще новичок, когда дело доходит до MPI, и я пытаюсь определить тип MPI, чтобы он соответствовал пользовательской структуре, которую я написал. Идея, стоящая за этим, заключается в том, что список студентов отправляется в несколько процессов, каждый из которых использует его для поиска, скажем, для определенного. Я специально инициализировал первый элемент в списке, чтобы проверить, работает ли программа. Функционал поиска реализован, но не используется.

Проблемы:

  • Я хотел убедиться, что мои данные правильно передаются процессам, поэтому я хотел распечатать их локальный список (local). Я обнаружил, что после первых нескольких записей все перепуталось, и я не могу понять, почему.
  • Есть ли способ иметь указатели вместо массивов символов внутри структуры? Насколько я читал, сделать это невозможно, потому что пространство памяти не является общим. это правильно?
  • Есть ли лучший способ инициализировать массив символов из указателя? Я думаю, что это использует много памяти.

Некоторые части кода были прокомментированы, например, принимающая часть процессов, в целях отладки. Я скомпилировал исходный код, используя mpicc students.c -Wall -Wextra -g, и выполнил его, используя mpiexec -n 4 ./a.out.

Код:

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NELEM 25
#define MAX_STR_LENGTH 30
#define MAX_FNAME_LENGTH 10
#define MAX_LNAME_LENGTH 10
#define MAX_YEAR_ID_LENTGH 3
#define MAX_CNP_LENGTH 13
#define MAX_YEARS 6
#define TAG 1
#define MASTER 0
#define TRUE 1
#define FALSE 0

#define FNAME_LABEL "First name"
#define LNAME_LABEL "Last name"
#define CNP_LABEL "CNP"
#define STUDIES_LABEL "Studies"
#define YEAR_LABEL "Year"

typedef struct
{
    char firstName[MAX_FNAME_LENGTH];
    char lastName[MAX_LNAME_LENGTH];
    char cnp[MAX_CNP_LENGTH];
    char studies[MAX_YEAR_ID_LENTGH];
    int year;
} Student;

void receive(MPI_Datatype type, int rank);
void send_data(Student data[], MPI_Datatype type, int num_procs);
void initialize(Student data[]);
char *rand_string(char *str, size_t size);
char *rand_string_alloc(size_t size);
int rand_year();
void initialize_student(Student *stud);
void fill_field(char data[], char *fill, int size, int max_size);
void print_field(char data[], int size, char *field_label);
void print_stud(Student stud);
int is_a_match(char lvalue[], char *rvalue);
Student *search_stud(char *cnp, Student students[], int list_size);
void initialize_custom_student(Student *stud);
void print_list(Student students[], int size, int rank);

int main(int argc, char **argv)
{
    srand(time(NULL));
    int num_procs, rank;

    Student to_send[NELEM];
    MPI_Datatype studentType, oldtypes[2];
    int blockcounts[2];

    /* MPI_Aint type used to be consistent with syntax of */
    /* MPI_Type_extent routine */
    MPI_Aint offsets[2], extent;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

    /* Setup description of the 4 MPI_FLOAT fields x, y, z, velocity */
    offsets[0] = 0;
    oldtypes[0] = MPI_CHAR;
    blockcounts[0] = 4;
    /* Setup description of the 2 MPI_INT fields n, type */
    /* Need to first figure offset by getting size of MPI_FLOAT */
    MPI_Type_extent(MPI_CHAR, &extent);

    offsets[1] = 4 * extent;
    oldtypes[1] = MPI_INT;
    blockcounts[1] = 1;

    /* Now define structured type and commit it */
    MPI_Type_struct(2, blockcounts, offsets, oldtypes, &studentType);
    MPI_Type_commit(&studentType);

    /* Initialize the particle array and then to_send it to each task */
    if (rank == MASTER)
    {
        initialize(to_send);
        send_data(to_send, studentType, num_procs);
        // print_list(to_send, NELEM, rank);
    }
    else
    {   
        // receive(studentType, rank);
    }

    //sanity-check printing
    if (rank == num_procs - 1)
    {
        receive(studentType, rank);
    }

    MPI_Type_free(&studentType);
    MPI_Finalize();
}

void receive(MPI_Datatype type, int rank)
{
    // printf("Process %d is awaiting data....!\n", rank);
    Student local[NELEM];
    MPI_Status status;
    MPI_Recv(local, NELEM, type, MASTER, TAG, MPI_COMM_WORLD, &status);
    print_list(local, NELEM, rank);

    // printf("[OK]:Proccess %d has finished receiving all the data!\n", rank);
}

void send_data(Student data[], MPI_Datatype type, int num_procs)
{
    // printf("Sending data....!\n");
    for (int i = 1; i < num_procs; i++)
    {
        MPI_Send(data, NELEM, type, i, TAG, MPI_COMM_WORLD);
    }
    // printf("[OK]:All data was sent!\n");
}

void initialize(Student data[])
{
    initialize_custom_student(&data[0]);

    printf("Initializing data....!\n");
    for (int i = 1; i < NELEM; i++)
    {
        initialize_student(&data[i]);
    }

    printf("[OK]:Data initialized!\n");
}

void initialize_custom_student(Student *stud)
{
    char *fName = "Some";
    int fNameSize = 5;

    char *lName = "Name";
    int lNameSize = 7;

    char *cnp = "1234";
    int cnpSize = 4;

    char *studies = "CS";
    int studiesSize = 2;

    fill_field(stud->firstName, fName, fNameSize, MAX_FNAME_LENGTH);
    fill_field(stud->lastName, lName, lNameSize, MAX_LNAME_LENGTH);
    fill_field(stud->cnp, cnp, cnpSize, MAX_CNP_LENGTH);
    fill_field(stud->studies, studies, studiesSize, MAX_YEAR_ID_LENTGH);
    stud->year = 4;
}

void initialize_student(Student *stud)
{
    int fNameSize = rand() % MAX_FNAME_LENGTH;
    char *firstname = rand_string_alloc(fNameSize);

    int lNameSize = rand() % MAX_LNAME_LENGTH;
    char *lastName = rand_string_alloc(MAX_LNAME_LENGTH);

    int cnpSize = rand() % MAX_CNP_LENGTH;
    char *CNP = rand_string_alloc(MAX_CNP_LENGTH);

    int studiesSize = rand() % MAX_YEAR_ID_LENTGH;
    char *studies = rand_string_alloc(MAX_YEAR_ID_LENTGH);

    fill_field(stud->firstName, firstname, fNameSize, MAX_FNAME_LENGTH);
    fill_field(stud->lastName, lastName, lNameSize, MAX_LNAME_LENGTH);
    fill_field(stud->cnp, CNP, cnpSize, MAX_CNP_LENGTH);
    fill_field(stud->studies, studies, studiesSize, MAX_YEAR_ID_LENTGH);
    stud->year = rand_year();

    free(firstname);
    free(lastName);
    free(CNP);
    free(studies);
}

void fill_field(char data[], char *fill, int size, int max_size)
{
    for (int i = 0; i < size; i++)
    {
        data[i] = fill[i];
    }

    for (int i = size; i < max_size; i++)
    {
        data[i] = '*';
    }
}

void print_field(char data[], int size, char *field_label)
{
    printf("    %s: ", field_label);
    for (int i = 0; i < size; i++)
    {
        char character = data[i];
        if (character == '*')
        {
            break;
        }

        printf("%c", character);
    }
    printf("\n");
}

char *rand_string(char *str, size_t size)
{
    const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK";
    if (size)
    {
        --size;
        for (size_t n = 0; n < size; n++)
        {
            int key = rand() % (int)(sizeof charset - 1);
            str[n] = charset[key];
        }
        str[size] = '\0';
    }
    return str;
}

char *rand_string_alloc(size_t size)
{
    char *s = malloc(size + 1);
    if (s)
    {
        rand_string(s, size);
    }
    return s;
}

int rand_year()
{
    return rand() % MAX_YEARS;
}

void print_stud(Student stud)
{
    print_field(stud.firstName, MAX_FNAME_LENGTH, FNAME_LABEL);
    print_field(stud.lastName, MAX_LNAME_LENGTH, LNAME_LABEL);
    print_field(stud.cnp, MAX_CNP_LENGTH, CNP_LABEL);
    print_field(stud.studies, MAX_YEAR_ID_LENTGH, STUDIES_LABEL);
}

Student *search_stud(char *cnp, Student students[], int list_size)
{
    Student *current = NULL;

    for (int i = 0; i < list_size; i++)
    {
        *current = students[i];
        if (is_a_match(current->cnp, cnp))
        {
            return current;
        }
    }

    return NULL;
}

int is_a_match(char lvalue[], char *rvalue)
{
    for (int i = 0; i < MAX_CNP_LENGTH; i++)
    {
        char left = lvalue[i];
        char right = rvalue[i];

        if (left == '0' || right == '0' || left != right)
        {
            return FALSE;
        }
    }

    return TRUE;
}

void print_list(Student students[], int size, int rank)
{
    for (int i = 0; i < size; i++)
    {
        print_stud(students[i]);
        printf("\n");
    }
}

Спасибо!


person CyberFox    schedule 17.03.2019    source источник
comment
if (left == '0' || right == '0' || left != right) Вы хотите 0 в качестве наполнителя вместо * ? [также: условие выглядит неправильно, вы, вероятно, хотите, чтобы обе стороны были 0]   -  person wildplasser    schedule 17.03.2019
comment
Вы правы, сэр. Как насчет потери данных после переноса?   -  person CyberFox    schedule 17.03.2019


Ответы (1)


Я нашел проблему. Это была ошибка выделения, эффективно выделяющая память для строки size + 1, хотя отступ был только для размера size в rand_string_alloc. Также весь метод fill_field можно заменить на strncpy(data, fill, max_size)

person CyberFox    schedule 24.03.2019