简体   繁体   English

通过C中的MPI_Send和MPI_recv进行操作

[英]Structs manipulation via MPI_Send and MPI_recv in C

I am still a newcomer when it comes to MPI and I am trying to define and MPI type to match a custom structure I wrote. 在MPI方面,我还是一个新手,我正在尝试定义MPI类型以匹配我编写的自定义结构。 The idea behind this is having a list of students sent to multiple processes, each using it to search, let's say for a particular one. 这背后的想法是有一个发送到多个进程的学生列表,每个进程使用它来搜索,让我们说一个特定的进程。 I have custom initialized the first element in the list so I can check if the program works. 我有自定义初始化列表中的第一个元素,所以我可以检查程序是否有效。 The search functionality has been implemented, but not used. 搜索功能已实现,但未使用。

The problems: 问题:

  • I wanted to ensure that my data is correctly passed to the processes, thus I wanted to print their local list (local). 我想确保我的数据正确传递给进程,因此我想打印他们的本地列表(本地)。 I have discovered that after the first few entries, everything gets messed up and I cannot seem to figure out why. 我发现在最初的几个条目之后,一切都搞砸了,我似乎无法弄清楚为什么。
  • Is there a way to have pointers instead of arrays of chars in side the struct? 有没有办法在结构中包含指针而不是字符数组? As far as I have read, there is no possible way to do this, because the memory space is not shared. 据我所知,没有可能的方法,因为内存空间不共享。 is that correct? 那是对的吗?
  • Is there a better way to initialize a char array from a pointer? 有没有更好的方法从指针初始化char数组? I think this is using a lot of memory. 我认为这是在使用大量内存。

Some portions of the code have been commented, such as the receive part of the processes, for debugging purposes. 为了调试目的,已注释了代码的某些部分,例如过程的接收部分。 I have compiled the source using mpicc students.c -Wall -Wextra -g and I have executed it using mpiexec -n 4 ./a.out . 我使用mpicc students.c -Wall -Wextra -g编译了源代码,并使用mpiexec -n 4 ./a.out执行了源代码。

Code: 码:

#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");
    }
}

Thanks! 谢谢!

I have found the problem. 我发现了这个问题。 It was an allocation error, effectively allocating memory for a string of size + 1 although it was indented for only for size size in rand_string_alloc . 这是一个分配错误,为一个size + 1的字符串有效地分配内存,尽管它仅为rand_string_alloc size rand_string_alloc Also, the entire method fill_field can be replaced with strncpy(data, fill, max_size) 同样,整个方法fill_field可以替换为strncpy(data, fill, max_size)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM