2014-03-28 81 views
1

我尝试将派生类型发送给处理器。该类型包含来自其他派生类型的对象。我从Examples: Struct Derived Data Type开始了这个例子。我添加我的代码。代码很长,但两种类型基本相同。我有Part对象,它也有一个Particle对象,我想发送Part。我的结果是在代码之后。MPI派生类型send

#include "mpi.h" 
#include <stdio.h> 
#define NELEM 25 

main(int argc, char *argv[]) { 
int numtasks, rank, source=0, dest, tag=1, i; 

typedef struct { 
float x, y, z; 
float velocity; 
int n, type; 
}   Particle; 

// Another struct to send 
typedef struct { 
char character; 
Particle part ; 
} Part ; 

MPI_Request send_req; 
MPI_Status stat; 


MPI_Init(&argc,&argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
MPI_Comm_size(MPI_COMM_WORLD, &numtasks); 

// Particle type 
Particle  particles; 
MPI_Datatype particletype, oldtypes[2]; 
int   blockcounts[2]; 
MPI_Aint  offsets[2], extent; 

offsets[0] = 0; 
oldtypes[0] = MPI_FLOAT; 
blockcounts[0] = 4; 
MPI_Type_extent(MPI_FLOAT, &extent); 
offsets[1] = 4 * extent; 
oldtypes[1] = MPI_INT; 
blockcounts[1] = 2; 

MPI_Type_struct(2, blockcounts, offsets, oldtypes, &particletype); 
MPI_Type_commit(&particletype); 


// Part type 
Part party , party_received; 
MPI_Datatype part_type,oldtype2[2]; 
int blockcount2[2]; 
MPI_Aint offset2[2],extent2; 

offset2[0] = 0; 
oldtype2[0] = MPI_CHAR ; 
blockcount2[0] = 1 ; 

MPI_Type_extent(particletype,&extent); 
offset2[1] = extent ; 
oldtype2[1] = particletype ; 
blockcount2[1] = 1 ; 

MPI_Type_struct(2,blockcount2,offset2,oldtype2,&part_type); 
MPI_Type_commit(&part_type); 


party.character= 'a'; 

if (rank == 0) { 

    particles.x = 1 * 1.0; 
    particles.y = 1 * -1.0; 
    particles.z = 1 * 1.0; 
    particles.velocity = 0.25; 
    particles.n = 1; 
    particles.type = 1 % 2; 

    party.part = particles; 

    printf("Derived data type sending, character: %c \n",party.character); 
    MPI_Isend(&party,1,part_type,1,tag,MPI_COMM_WORLD,&send_req); 
    printf("particles sent %f %f %f %f %d %d \n", 
         party.part.x,party.part.y,party.part.z, 
         party.part.velocity,party.part.n,party.part.type); 
    } 
if(rank == 1) { 
    MPI_Recv(&party_received, 1, part_type, 0, tag, MPI_COMM_WORLD, &stat); 
    printf("derived part type received character %c \n",party_received.character) ; 
    printf("particles %f %f %f %f %d %d \n", 
      party_received.part.x,party_received.part.y,party_received.part.z, 
      party_received.part.velocity,party_received.part.n,party_received.part.type); 
} 
MPI_Type_free(&particletype); 
MPI_Finalize(); 
} 

结果每次都会改变。最后一个是:

Derived data type sending, character: a 
particles sent 1.000000 -1.000000 1.000000 0.250000 1 1 
derived part type received character a 
particles 0.000000 -2686527813451776.000000 0.000000 0.000000 1 1 

虽然character是真的,为什么Particle对象都没有?我如何纠正它?

回答

3

您正在计算错误的偏移量。

offset2[0] = 0; 
oldtype2[0] = MPI_CHAR ; 
blockcount2[0] = 1 ; 

MPI_Type_extent(particletype,&extent); 
offset2[1] = extent ; <--- WRONG 
oldtype2[1] = particletype ; 
blockcount2[1] = 1 ; 

这里的偏移量不是结构第二个成员的范围。这是第一个的程度+可能是一些填充(在你的情况下 - 3个字节的填充)。

为了防止类似的错误在未来,我会建议你使用offsetof()代替:

#include <stddef.h> 

offset[0] = offsetof(Part, character); 
offset[1] = offsetof(Part, part); 

计算使用程度的偏移是概念错误的,因为没有保证内部结构使用的填充程度相匹配。一个简单的例子:在大多数系统中,MPI_CHAR具有1字节的范围,但如果由于对齐要求而具有像struct { char a; int b; }这样的结构,则在ab之间将会有3个字节的填充。这同样适用于您的Part结构 - part成员使用填充进行对齐,因为Particle的第一个成员是浮点数。

如果您的系统没有offsetof,你可以用MPI_Get_address替换为:

Part party; 
MPI_Aint base, member_offset; 

MPI_Get_address(&party, &base); 

MPI_Get_address(&party.character, &member_offset); 
offset[0] = member_offset - base; 

MPI_Get_address(&party.part, &member_offset); 
offset[1] = member_offset - base; 
+0

感谢。它以这种方式工作。 – yossarianlives