概述:我正在测试使用 MPI_Type_create_struct() 创建的数据类型是否正确,因此会发送正确的值。我无法将存储在数组中的值传输到其他处理器上。我认为这可能是每个结构体绑定(bind)中数组的内存地址以及用于创建数据类型 mpibound 的数组索引[]中存储的偏移量的问题。
问题: 我正在使用 MPI 开发一个程序,我的最终目标是使用 MPI_Gatherv() 从下面声明的名为“bound”的结构数组中收集值。
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() 时,存储在作为我使用的缓冲区结构一部分的数组中的值不会更新,但整数值 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 的进程上,n 的值从等级 0 更新为广播,但 lat 和 lon 数组的第一个元素仍然是 0。
如果你能帮助我,我非常感谢它已经为此奋斗了几天!我尽力保持简短,这是我能够创建的最好版本。
感谢您的阅读!
最佳答案
正如 Zulan 所指出的,您的代码中有些内容没有什么意义。但主要问题在于
void CreateBoundType (struct bound a_bound) {
// HERE HERE HERE HERE
您正在按值传递结构,这意味着 MPI 数据类型 mpibound
是根据值副本的内存地址构造的。该副本包含相同的 label
、lat
和 lon
指针值,但基址将位于其他位置。因此,您不能使用该数据类型在 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 数据类型。
既然您仍然为 lat
和 lon
分配了全部内存,为什么不在结构中简单地使用数组呢?
struct bound {
int n;
char name[10];
double lat[NPT_MAX];
double lon[NPT_MAX];
};
不要忘记在创建 MPI 结构数据类型后使用 MPI_Type_create_resized
将其大小调整为 sizeof(structbound)
。
另外,请注意,在 C 中,指向结构的指针是指向其第一个元素的指针,因此无需显式计算 n
的偏移量 - 通过以下方式保证它为 0:语言。
关于c - 在 C 中使用 MPI_Type_create_struct() 传输包含动态数组的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41225554/