如何使用结构指针数组 MPI 发送和接收嵌套结构?

How to MPI Send and Recv Nested struct with Pointer Array of Struct?

下面是结构声明和代码:

struct cell_struct {
    int x, y;
    bool isWater, isPort, isRock;
    struct port_struct port_data;
    struct ship_struct *ships_data[MAX_SHIPS_PER_CELL];
    int number_ships;
};

struct ship_struct {
    int route, totalHoursAtSea, hoursAtSeaThisJourney, id, numberPassengers, euclideanPlannedDistance;
    bool willMoveThisTimestep;
};

// Data associated with each port
struct port_struct {
    int shipsInPastHundredHours[10];
    int port_index, passengersShipped;
    double totalFeesCollected;
};

struct cell_struct *domain_test;

domain_test = (struct cell_struct *) malloc(
            sizeof(struct cell_struct) * (mpi_info->local_size_x + 2) * simulation_configuration->size_y);

使用下面的 Send 和 Recv,我能够发送和接收,domain_test,但在发送和接收后无法从 domain_test 访问 ships_data。有什么帮助吗?

MPI_Send(&domain_test[mpi_info->local_size_x_end * simulation_configuration->size_y + i], sizeof(struct cell_struct), MPI_BYTE, 1, i, MPI_COMM_WORLD);

MPI_Recv(&domain_test[0],sizeof(struct cell_struct) * simulation_configuration->size_y, MPI_BYTE, 0, 0, MPI_COMM_WORLD, &status);


您的代码中的主要问题是 cell_struct 存储了一个静态数组 指向船舶 的指针,这意味着船舶本身的数据可能到处都是这个地方。如果您改为存储船舶的静态数组,,您将有一个连续的内存块需要发送。您甚至可以使用 count=sizeof(cell_struct)type=MPI_BYTE 然后(就像您现在所做的那样)或@Gilles 指示的任何方法发送它。

您的代码的结果是现在在分配给单元格时会复制飞船,而不仅仅是设置指针。如果船只的数据很少,这不是问题,如此处所示,但如果复制成本很高,可能会使代码变慢。

对于系统之间复杂数据结构的传输,如果您不希望按照 Jonas 的建议将结构安排为一个连续的内存块,那么这就是某种形式的序列化发挥作用的地方。

对于 C 编程语言,要使用序列化技术,您几乎必须坚持模式优先,例如 Google 协议缓冲区(请参阅 C version and Google's page)。 Java 和 C# 等其他语言内置了序列化功能,因此您可以选择代码优先或模式优先序列化。

最简短的概述是:

  1. 编写描述数据结构的模式文件(GPB 的 .proto),就像在 C 中使用 struct{} 定义一样
  2. 使用提供的工具编译模式以输出确实使用 struct{} 定义数据结构的 C 代码,以及一组可以将它们序列化/反序列化为线格式的函数
  3. 在您的项目中使用生成的 C 代码。您使用生成的结构根据需要声明变量,并使用序列化/反序列化函数生成/消耗 MPI_BYTE 缓冲区,
  4. 您使用 MPI
  5. 发送/接收这些 MPI_BYTE 缓冲区

这有一些基本的优点:

  • 您的分布式系统可以是异构的。因此,不必在 PC 上使用 64 位 C 运行ning 运行ning Windows 10 64 位在任何地方都使用相同的编译器编译,您可以混合搭配语言、机器类型、操作系统、编译器等;
  • 您可以合理安排数据结构,而不是为了在连续内存中实现存储而使它们更加模糊。

我的猜测是,如果您为了发送/接收数据而重新安排内存以构建/解构连续内存,您会更好(从 运行 时间长度点开始的观点)与像 GPB 这样的序列化技术。