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

Все още съм новодошъл, що се отнася до MPI, и се опитвам да дефинирам типа MPI, за да съответства на персонализирана структура, която написах. Идеята зад това е да има списък от студенти, изпратен до множество процеси, като всеки го използва за търсене, да кажем за конкретен. Инициализирах по избор първия елемент в списъка, за да мога да проверя дали програмата работи. Функцията за търсене е внедрена, но не се използва.

Проблемите:

  • Исках да се уверя, че данните ми се предават правилно на процесите, затова исках да отпечатам техния локален списък (локален). Открих, че след първите няколко влизания всичко се обърква и не мога да разбера защо.
  • Има ли начин да има указатели вместо масиви от знаци встрани от структурата? Доколкото прочетох, няма възможен начин да стане това, защото пространството в паметта не е споделено. вярно ли е?
  • Има ли по-добър начин за инициализиране на char масив от указател? Мисля, че това използва много памет.

Някои части от кода са коментирани, като частта за получаване на процесите, за целите на отстраняването на грешки. Компилирах източника с помощта на 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