使用mpi_type_create_struct()将包含动态数组的结构转移



概述:我正在测试使用mpi_type_create_struct()创建的数据类型是正确的,因此发送正确的值。我在将存储在数组中的值转移到其他处理器上时遇到了麻烦。我认为,这可能是每个结构绑定中的数组的内存地址以及存储在数组索引[]中的偏移量的问题,用于创建数据类型mpibound。

问题:我正在使用MPI进行程序,我的最终目标是使用MPI_GATHERV()从下面声明的一个称为BOND的结构中收集值。

struct bound {
   int      n;
   char*    name;
   double*  lat;
   double*  lon;
};

我已经创建了一个测试程序,以确保我正确使用了mpi_type_create_struct()。我称为mpi_type_create_struct()的函数在下面写入。

 void CreateBoundType (struct bound a_bound) {
    int blocklens[4];              /*Block Lengths of data in structure*/
    MPI_Datatype old_types[4];     /*Data types of data in structure*/
    MPI_Aint indices[4];           /*Byte displacement of each piece of data*/
    MPI_Aint addr1, addr2, addr3, addr4, baseaddr;
   /*Set block lengths*/
   blocklens[0] = 1;
   blocklens[1] = 10;
   blocklens[2] = NPT_MAX;
   blocklens[3] = NPT_MAX;
   /*Set Data Types*/
   old_types[0] = MPI_INT;
   old_types[1] = MPI_CHAR;  
   old_types[2] = MPI_DOUBLE;  
   old_types[3] = MPI_DOUBLE;  
   /*Set byte displacement for each piece of data in structure*/
   /*!!!!!I expect that the following 8 lines cause my problem!!!!!!*/
   MPI_Get_address ( &a_bound,         &baseaddr);
   MPI_Get_address ( &a_bound.num_pts, &addr1);
   MPI_Get_address ( a_bound.label,    &addr2);
   MPI_Get_address ( a_bound.lat,      &addr3);
   MPI_Get_address ( a_bound.lon,      &addr4);
   indices[0] = addr1 - baseaddr;
   indices[1] = addr2 - baseaddr;
   indices[2] = addr3 - baseaddr;
   indices[3] = addr4 - baseaddr;
   /*Create structure type in MPI so that we can transfer boundaries between nodes*/
   MPI_Type_create_struct(4,blocklens,indices,old_types,&mpibound);
   MPI_Type_commit(&mpibound); 
   return;
}

当我尝试使用我创建的数据类型(这是一个全局变量,mpibound)时,在呼叫mpi_bcast()的drope are in of buffer struct i使用的阵列中存储的值未更新,但是整数值n(n是数组的长度)确实在所有处理器上都会更改。因此,我认为我的问题与用于定义mpibound的偏移(指数[4])有关。

下面我写了一个主功能,该功能显示了我如何称呼此功能并设置结构。(我已经省略了MPI_Init和其他此类功能的电话,以使其尽可能短)

int main (int argc, char **argv) {
   /*Initialise MPI etc*/...
   /*Create structure to broadcast*/
   struct bound my_bound;
   my_bound.name  = strdup(string);
   my_bound.lat   = malloc(NPT_MAX*sizeof(double));
   my_bound.lon   = malloc(NPT_MAX*sizeof(double));
   if(rank == 0) {
      my_bound.n      = 5;
      my_bound.lat[0] = 2.6;
      my_bound.lon[0] = 4.2;
   }
   /*Call the function that creates the type mpibound*/
   CreateBoundType(my_bound);
   /*Create buffer to be used in a Broadcast from the root processor (rank 0)*/
   struct bound *buff = malloc(sizeof(struct bound));
   buff->lat = malloc(NPT_MAX*sizeof(double));
   buff->lon = malloc(NPT_MAX*sizeof(double));
   buff = &my_bound;
   /*Cast values in buffer from proc 0 to all others*/
   MPI_Bcast(buff,1,mpibound,0,MPI_COMM_WORLD);
   /*Print values and checks, free memory etc*/...
   return(EXIT_SUCCESS);
}

在拨打mpi_bcast的呼叫之后,将一些打印语句放置在级别> 0的procs上,n的值已从等级0更新为该广播,但LAT和LON阵列的第一个元素仍然为0。p>如果您能帮助我,我非常感谢它已经挣扎了几天!我试图尽我所能,这是我能够创建的最佳版本。

感谢您的阅读!

正如Zulan指出的那样,您的代码中有些事情毫无意义。但是主要问题在于

void CreateBoundType (struct bound a_bound) {
//                    HERE HERE HERE HERE

您正在按值传递结构,这意味着MPI数据类型mpibound是从值副本的内存地址构建的。该副本包含labellatlon的相同指针值,但基地将位于其他地方。因此,您不能使用该数据类型在main中发送结构实例,因为偏移无效。

您应该做的是通过地址传递结构。更改很小:

void CreateBoundType (struct bound *a_bound) {
   ...
   MPI_Get_address(a_bound,           &baseaddr);
   MPI_Get_address(&a_bound->n, &addr1);
   MPI_Get_address(a_bound->label,    &addr2);
   MPI_Get_address(a_bound->lat,      &addr3);
   MPI_Get_address(a_bound->lon,      &addr4);
   ...
}
...
/*Call the function that creates the type mpibound*/
CreateBoundType(&my_bound);
...

请注意,您将无法实现最终目标来收集(v),因为在收集操作创建数组时,偏移仅适用于单个实例。数组的每个元素都可能具有不同的偏移,因此需要单独的MPI数据类型。

既然您正在为latlon中的每一个分配全部内存,那么为什么不简单地在结构中使用数组?

struct bound {
   int     n;
   char    name[10];
   double  lat[NPT_MAX];
   double  lon[NPT_MAX];
};

不要忘记使用MPI_Type_create_resized创建为sizeof(struct bound)后的MPI结构数据类型大小。

另外,请注意,在C中,指向结构的指针是指向其第一个元素的指针,因此无需明确计算n的偏移 - 它可以通过语言为0。

<</p>

相关内容

  • 没有找到相关文章

最新更新