在 C 中通过 MPI_Send 和 MPI_recv 进行结构化操作

Structs manipulation via MPI_Send and MPI_recv in C

当谈到 MPI 时,我仍然是一个新手,我正在尝试定义和 MPI 类型以匹配我编写的自定义结构。这背后的想法是将学生列表发送到多个进程,每个进程都使用它来搜索,比方说搜索一个特定的进程。我已经自定义初始化了列表中的第一个元素,这样我就可以检查程序是否有效。搜索功能已实现,但尚未使用。

问题:

代码的某些部分已被注释,例如进程的接收部分,以供调试之用。我使用 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] = '[=12=]';
    }
    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");
    }
}

谢谢!

我找到问题了。这是一个分配错误,有效地为 size + 1 的字符串分配了内存,尽管它在 rand_string_alloc 中缩进的大小仅为 size。此外,整个方法 fill_field 可以替换为 strncpy(data, fill, max_size)