首页 > 解决方案 > 在一条消息中发送带有常量标头的可变长度向量

问题描述

我有 n workers, 1 master(排名 0),需要通过 MPI 从 n 发送消息workersmaster. 消息格式是可变长度向量 ( float *dta) 和恒定大小的标头struct { int32_t x, int32_t y } dtaHdr

master 只是遍历传入的结果并处理它们。能够将哪个dtaHdr与哪个相关联是很重要的dta

我知道如何:

  1. MPI_Datatype为常量大小创建dtaHdr并通过 P2P MPI_Send/发送MPI_Recv
  2. MPI_Float通过 P2P MPI_Send/发送任何数据类型(例如 )的可变长度向量MPI_Recv

问题是我不知道如何结合这两种方法。

我知道我可以:

我的问题是:我如何以 MPI 惯用的方式发送一个可识别的逻辑消息,其中包含一种类型的恒定大小的标头和第二种类型的可变大小的向量。

标签: cmpi

解决方案


该程序使用MPI_PackandMPI_Unpack在同一消息中发送两种不同的类型:

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

#define ARRAY_SIZE(array) \
    (sizeof(array) / sizeof(array[0]))

struct data_header {
    int32_t x;
    int32_t y;
};

MPI_Datatype dt_header;
MPI_Datatype dt_vector;

void sendmsg(void) {
    struct data_header header = { 1, 2 };
    float example[] = { 1.0, 2.0, 3.0, 4.0 };
    char buffer[4096];
    int position;

    MPI_Pack(&header, 1, dt_header, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
    MPI_Pack(example, 1, dt_vector, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
    MPI_Send(buffer, position, MPI_PACKED, 0, 0, MPI_COMM_WORLD);
}

void recvmsg(void) {
    struct data_header header;
    float example[4];
    char buffer[4096];
    int position = 0;

    MPI_Recv(buffer, sizeof(buffer), MPI_PACKED, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    MPI_Unpack(buffer, sizeof(buffer), &position, &header, 1, dt_header, MPI_COMM_WORLD);
    MPI_Unpack(buffer, sizeof(buffer), &position, example, 1, dt_vector, MPI_COMM_WORLD);

    printf("x = %d, y = %d\n", header.x, header.y);
    for (int index = 0; index < ARRAY_SIZE(example); index++) {
        printf("%f ", example[index]);
    }
    printf("\n");
}

int main(void) {
    int world_size;
    int world_rank;

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    MPI_Type_contiguous(2, MPI_INT, &dt_header);
    MPI_Type_commit(&dt_header);
    MPI_Type_contiguous(4, MPI_FLOAT, &dt_vector);
    MPI_Type_commit(&dt_vector);

    if (0 == world_rank) {
        recvmsg();
    }
    else {
        sendmsg();
    }

    MPI_Finalize();

    return 0;
}

输出

x = 1, y = 2
1.000000 2.000000 3.000000 4.000000 

这实际上只是概念验证代码。希望它能帮助您找到您正在寻找的解决方案。

笔记

此代码不进行错误检查,不应在生产环境中使用。


推荐阅读