大小灵活的结构的MPI派生数据类型 我试图在C++中发送/ReV这样的数据结构: /*伪代码*/ 常量int N=getN();//在编译时不可用 常量int M=getM(); 结构包{ int foo; 双杠; /*我知道数组成员不是这样工作的, 这是伪代码*/ 整数触发器[N]; 双泡[M]; };
由于大小灵活的结构的MPI派生数据类型 我试图在C++中发送/ReV这样的数据结构: /*伪代码*/ 常量int N=getN();//在编译时不可用 常量int M=getM(); 结构包{ int foo; 双杠; /*我知道数组成员不是这样工作的, 这是伪代码*/ 整数触发器[N]; 双泡[M]; };,c++,mpi,memory-alignment,C++,Mpi,Memory Alignment,由于M和N在运行时是常量,因此我可以执行MPI\u Type\u create\u struct(),并且新的数据类型在整个过程中都会很好 我的问题是如何实现上述数据结构 std::vector无法工作,因为它不是串行的 灵活的数组成员如 > [/]>或 [0 ]是C++中的未定义行为,它对M和 N 因此,我必须使用malloc(): 类包{ 公众: //缓冲区中[]:条、气泡[]、foo、flop[] //按照这个顺序,一个直接跟在另一个后面。 包(): 缓冲区((双*)malloc((M+1
M
和N
在运行时是常量,因此我可以执行MPI\u Type\u create\u struct()
,并且新的数据类型在整个过程中都会很好
我的问题是如何实现上述数据结构
std::vector
无法工作,因为它不是串行的
灵活的数组成员如<> > [/]>或<代码> [0 ]<代码>是C++中的未定义行为,它对<
:malloc()
类包{
公众:
//缓冲区中[]:条、气泡[]、foo、flop[]
//按照这个顺序,一个直接跟在另一个后面。
包():
缓冲区((双*)malloc((M+1)*sizeof(双)*
(N+1)*sizeof(int)),
条(缓冲器),气泡(缓冲器+1),
foo((int*)(blep+M)),
flop(foo+1){}
~Package(){
自由(缓冲);
}
//构造/释放派生数据类型
静态无效初始化(未签名inN、未签名inM){
N=客栈;
M=inM;
MPI_Aint偏移量[2]={0,(int)(sizeof(double))*(M+1)};
int块[2]={M+1,N+1};
MPI_数据类型[2]={MPI_DOUBLE,MPI_INT};
MPI类型创建结构(2、块、偏移、类型和packageType);
MPI_类型_提交(&packageType);
}
静态void finalize(){
无MPI类型(和packageType);
}
int发送(int秩,int标记){
返回MPI_发送(缓冲区,1,packageType,
排名、标签、MPI_COMM_WORLD);
}
int recv(int秩,int标记){
返回MPI_Recv(缓冲区,1,packageType,
排名、标签、MPI_COMM_WORLD、,
MPI_状态_忽略);
}
私人:
双*缓冲器;
静态int-M;
静态int N;
静态MPI_数据类型packageType;
公众:
//接口变量
双*常数条;
双*常量气泡;
int*const foo;
int*const触发器;
};
int包::N=0;
int包::M=0;
MPI_数据类型包::packageType=MPI_字符;
我测试了上面的代码,它似乎工作正常,但我不确定我是否在做一些实际上是未定义的行为。具体而言:
sizeof()
进行MPI\u Type\u create\u struct()
可以吗?我发现一些示例使用了MPI\u Type\u get\u extent()
,我不知道有什么区别静态成员中是否是一个好主意。相反,我发现的示例将其作为一个论点传递。有什么具体的理由这样做吗
struct
的方法一样可移植,但也许我遗漏了什么A
和B
,而不是double
和int
。然后可能会发生类型为B
的对象(您在A
s之后为其分配空间)未对齐的情况。在某些体系结构上,尝试在(4N+2)字节边界处访问此类对象(例如,int
)将导致总线错误。因此,在一般情况下,必须确保在第一个B
对象之前填充正确。当您使用struct
时,编译器会为您执行此操作
二,。您访问缓冲区的方式是UB。基本上你是这样做的:
double*buffer=reinterpret_cast(malloc(…);
双*条=缓冲器;
int*foo=reinterpret_cast(缓冲区+1);
做某事(缓冲);
双杠_值=*杠;//这是UB
int foo_value=*foo;//我也是
这里的问题是在*bar
和*foo
处没有类型为double
和int
的对象。您可以使用placementnew
创建它们:
char* buffer = reinterpret_cast<char*>(malloc(...));
double* bar = new(buffer) double;
int* foo = new(buffer + sizeof(double)) int;
char*buffer=reinterpret_cast(malloc(…);
双*条=新(缓冲区)双;
int*foo=new(buffer+sizeof(double))int;
请参阅
对于数组,可以使用std::uninitialized_default_construct
构造给定范围内的对象
我不确定将新数据类型存储在静态成员中是否是一个好主意。相反,我发现的示例将其作为一个论点传递。有什么具体的理由这样做吗
如果N
和M
是静态的,那么将packageType
也设置为静态似乎很好。如果只有一种类型的包
具有固定的N
和M
,则可能希望避免每次构造包时调用MPI\u type\u create\u struct
,以创建基本相同的MPI数据类型
但是这种设计看起来不太好:在第一次构造之前应该调用initialize()
。可能您可以创建一个工厂,首先创建MPI数据类型,然后根据用户请求使用类似于Package make\u Package()
的东西构造Package
。那么每个工厂都可以有自己的非静态N
和M
@Evg你所说的std::vector
不是串行的是什么意思std::vector
本质上是一个标准数组的奇特接口。。。它只是提供了一些功能,让你的生活更轻松。。。请看一看(它提供了对底层数组的访问)@Evg您应该只对包含内部数据的类使用static
关键字