包含动态分配的数组的自定义数据类型的MPI_reduce():分段错误
我不明白为什么MPI_Reduce()在我使用包含动态分配的数组的自定义MPI数据类型时会立即执行分段错误。 有人知道吗 ? 以下代码在MPI_Reduce()内部与2个处理器崩溃。 但是,如果我删除成员double * d int MyType并相应地更改运算符和MPI类型例程,则减少完成没有任何问题。
使用动态分配的数组是否存在问题,或者我的工作存在根本错误:
#include #include #include typedef struct mytype_s { int c[2]; double a; double b; double *d; } MyType; void CreateMyTypeMPI(MyType *mt, MPI_Datatype *MyTypeMPI) { int block_lengths[4]; // # of elt. in each block MPI_Aint displacements[4]; // displac. MPI_Datatype typelist[4]; // list of types MPI_Aint start_address, address; // use for calculating displac. MPI_Datatype myType; block_lengths[0] = 2; block_lengths[1] = 1; block_lengths[2] = 1; block_lengths[3] = 10; typelist[0] = MPI_INT; typelist[1] = MPI_DOUBLE; typelist[2] = MPI_DOUBLE; typelist[3] = MPI_DOUBLE; displacements[0] = 0; MPI_Address(&mt->c, &start_address); MPI_Address(&mt->a, &address); displacements[1] = address - start_address; MPI_Address(&mt->b,&address); displacements[2] = address-start_address; MPI_Address(&mt->d, &address); displacements[3] = address-start_address; MPI_Type_struct(4,block_lengths, displacements,typelist,MyTypeMPI); MPI_Type_commit(MyTypeMPI); } void MyTypeOp(MyType *in, MyType *out, int *len, MPI_Datatype *typeptr) { int i; int j; for (i=0; i < *len; i++) { out[i].a += in[i].a; out[i].b += in[i].b; out[i].c[0] += in[i].c[0]; out[i].c[1] += in[i].c[1]; for (j=0; j<10; j++) { out[i].d[j] += in[i].d[j]; } } } int main(int argc, char **argv) { MyType mt; MyType mt2; MPI_Datatype MyTypeMPI; MPI_Op MyOp; int rank; int i; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); mt.a = 2; mt.b = 4; mt.c[0] = 6; mt.c[1] = 8; mt.d = calloc(10,sizeof *mt.d); for (i=0; i<10; i++) mt.d[i] = 2.1; mt2.a = 0; mt2.b = 0; mt2.c[0] = mt2.c[1] = 0; mt2.d = calloc(10,sizeof *mt2.d); CreateMyTypeMPI(&mt, &MyTypeMPI); MPI_Op_create((MPI_User_function *) MyTypeOp,1,&MyOp); if(rank==0) printf("type and operator are created now\n"); MPI_Reduce(&mt,&mt2,1,MyTypeMPI,MyOp,0,MPI_COMM_WORLD); if(rank==0) { for (i=0; i<10; i++) printf("%f ",mt2.d[i]); printf("\n"); } free(mt.d); free(mt2.d); MPI_Finalize(); return 0; }
我们来看看你的结构:
typedef struct mytype_s { int c[2]; double a; double b; double *d; } MyType; ... MyType mt; mt.d = calloc(10,sizeof *mt.d);
并且您将此结构描述为MPI类型:
displacements[0] = 0; MPI_Address(&mt->c, &start_address); MPI_Address(&mt->a, &address); displacements[1] = address - start_address; MPI_Address(&mt->b,&address); displacements[2] = address-start_address; MPI_Address(&mt->d, &address); displacements[3] = address-start_address; MPI_Type_struct(4,block_lengths, displacements,typelist,MyTypeMPI);
问题是,这个MPI结构只会应用于您在此处定义中使用的结构的一个实例。 你无法控制calloc()
决定从哪里获取内存; 它可以在虚拟内存中的任何地方。 您创建和实例化的下一个类型, d
数组的位移将完全不同; 甚至使用相同的结构,如果使用当前mt
realloc()
更改数组的大小,它可能最终会有不同的位移。
因此,当您使用其中一种类型发送,接收,减少或其他任何内容时,MPI库将尽职尽责地转移到可能无意义的位移,并尝试从那里读取或写入,这可能会导致段错误。
请注意,这不是MPI的事情; 在使用任何低级通信库时,或者尝试从磁盘写出/读入时,你会遇到同样的问题。
您的选项包括手动将arrays“编组”到消息中,或者使用其他字段或不使用; 或者在d所在的位置添加一些可预测性,例如通过将其定义为某个已定义的最大大小的数组。