2014-03-28 79 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