MPI_reduce(),自定义数据类型包含动态分配的ARAY:分段错误
我不明白为什么当我使用包含动态分配数组的自定义MPI数据类型时,MPI_Reduce()就会出现分段错误。有人知道吗?以下代码在MPI_Reduce()内的2个处理器上崩溃。 但是,如果我删除了成员double*d int MyType并相应地更改了运算符和MPI类型例程,那么就不会出现任何问题 使用动态分配的阵列是否存在问题,或者我所做的工作是否存在根本性问题:MPI_reduce(),自定义数据类型包含动态分配的ARAY:分段错误,c,parallel-processing,mpi,C,Parallel Processing,Mpi,我不明白为什么当我使用包含动态分配数组的自定义MPI数据类型时,MPI_Reduce()就会出现分段错误。有人知道吗?以下代码在MPI_Reduce()内的2个处理器上崩溃。 但是,如果我删除了成员double*d int MyType并相应地更改了运算符和MPI类型例程,那么就不会出现任何问题 使用动态分配的阵列是否存在问题,或者我所做的工作是否存在根本性问题: #include <stdio.h> #include <stdlib.h> #include <mp
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
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;
}
#包括
#包括
#包括
类型定义结构mytype\s
{
int c[2];
双a;
双b;
双*d;
}MyType;
void CreateMyTypeMPI(MyType*mt,MPI\U数据类型*MyTypeMPI)
{
每个块中elt的int block_长度[4];/#
MPI_Aint位移[4];//位移。
MPI_数据类型类型列表[4];//类型列表
MPI_Aint start_address,address;//用于计算显示。
MPI_数据类型myType;
块长度[0]=2;
块长度[1]=1;
块长度[2]=1;
块体长度[3]=10;
类型列表[0]=MPI_INT;
类型列表[1]=MPI\U双精度;
类型列表[2]=MPI\U双精度;
类型列表[3]=MPI\U双精度;
位移[0]=0;
MPI\U地址(&mt->c和&start\U地址);
MPI\U地址(&mt->a和地址);
位移[1]=地址-起始地址;
MPI_地址(&mt->b和&Address);
位移[2]=地址-起始地址;
MPI_地址(&mt->d和地址);
位移[3]=地址-起始地址;
MPI类型结构(4,块长度、位移、类型列表、MyTypeMPI);
MPI_Type_commit(MyTypeMPI);
}
void MyTypeOp(MyType*in,MyType*out,int*len,MPI_数据类型*typeptr)
{
int i;
int j;
对于(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];
对于(j=0;j让我们看看您的结构:
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结构只会应用于您在此处定义中使用的结构的一个实例。您对wherecalloc()完全没有控制权
决定从中获取内存;它可以位于虚拟内存中的任何位置。您创建和实例化的下一种类型,您的d
数组的位移将完全不同;如果您使用realloc()更改数组的大小,甚至使用相同的结构
对于当前的mt
,它可能最终会产生不同的位移
因此,当您使用这些类型之一发送、接收、减少或执行任何其他操作时,MPI库将尽职尽责地转到一个可能没有意义的位移,并尝试从那里读取或写入,这可能会导致SEGFULT
请注意,这不是MPI问题;在使用任何低级通信库时,或者在尝试从磁盘进行写/读时,都会遇到同样的问题
您的选项包括手动“编组”将数组放入消息中,无论是否包含其他字段;或者为d的位置添加一些可预测性,例如将其定义为某个已定义的最大大小的数组。哦,我想我明白了:动态分配的内存块与我的结构的前几个成员不连续,但是MPI使用位移array,我给了他,试图访问成员“b”后的10 MPI_DOUBLE,这会导致分段错误。那么如何使用动态数组减少这种结构呢?您应该将MyType.d设置为数组。或者,如果您需要动态内存,则使用memcpy.Y创建一个包含结构内所有数据的内存包,并指向它es我需要数组是动态的,上面的代码是jsut的一个小例子,在我的实际代码中有许多大型数组因此需要动态分配。你能更具体地说明你对memcpy的建议吗?不要使用memcpy
。MPI提供MPI\u Pack
和MPI\u Unpack
调用来执行端口可以将数据(非)打包到用户提供的内存缓冲区中。基本思想是自行构造消息,而不是创建数据类型,因为MPI根本无法遵循指针引用。MPI\u Pack()
和MPI\u Unpack()的组合
提供了执行便携式数据编组的方法。必须在调用MPI\u Reduce()
之前打包数据,并且自定义操作处理程序必须解压缩每个数据元素。