为包含动态数组的结构创建MPI类型 [英] Create MPI type for struct containing dynamic array
本文介绍了为包含动态数组的结构创建MPI类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我试图发送一个将其中一个成员作为动态数组的结构,但此数组似乎发送不正确。对如何做到这一点有什么建议吗?
这是我拥有的:
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType(MPI_Datatype* newType, int cLen, struct bar* msg)
{
int blockLengths[3] = {1, 1, cLen};
MPI_Datatype types[3] = {MPI_INT, MPI_INT, MPI_INT};
MPI_Aint offsets[3];
MPI_Aint addrB, addrC;
MPI_Address(&(msg->b), &addrB);
MPI_Address(msg->c, &addrC);
offsets[0] = offsetof(struct bar, a);
offsets[1] = offsetof(struct bar, b);
offsets[2] = addrC - addrB;
MPI_Type_create_struct(3, blockLengths, offsets, types, newType);
MPI_Type_commit(newType);
}
void main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
int cLen = argv[0];
MPI_Datatype MPI_BAR_TYPE;
struct bar* msg = malloc(sizeof(*msg));
msg->c = malloc(sizeof(int) * cLen);
defineMPIType(&MPI_BAR_TYPE, cLen, msg);
if (rank == 0)
{
msg->a = 1;
msg->b = 2;
for (int i = 0; i < cLen; ++i)
msg->c[i] = i;
MPI_Send(msg, 1, MPI_BAR_TYPE, 1, 111, MPI_COMM_WORLD);
}
else
{
MPI_Status stat;
MPI_Recv(msg, 1, MPI_BAR_TYPE, 0, 111, MPI_COMM_WORLD, &stat);
}
printf("Rank %d has c = [", rank);
for (int i = 0; i < cLen; ++i)
printf("%d, ", msg->c[i]);
printf("]
");
free(msg);
MPI_Type_free(&MPI_BAR_TYPE);
MPI_Finalize();
}
成员a
和b
已正确发送,但c
未正确发送。
推荐答案
您的代码中存在一些问题,甚至忽略了类型本身的问题:
- 第一个问题是,您仅在进程#0上为
c
数组分配了内存,然后您(试图)将此数据发送到进程#1。但是进程#1没有分配任何内存来存储消息。因此,即使发送方式正确,代码也会失败。 - 以
MPI_
开头的名称是为MPI库保留的,因此您不能随心所欲地使用它们。您必须为您的MPI_BAR_TYPE
找到其他名称。 - 这一行让我有点困惑:
int cLen = argv[0];
我想您想要从命令行读取要分配的数组的大小,在这种情况下,可能应该是这样的:int clen = atoi(argv[1]);
(忘记了需要正确处理的有效性测试.) - 您仅测试该进程是否为0级进程,这意味着如果您出于某种原因启动了3个进程,2级进程将永远等待来自0级进程的永远不会到达的消息。
- 最后是数组本身:在您的代码中,指针
c
和c
指向的数据之间有一个很大的念力。您的结构嵌入了指针,但没有嵌入指向的内存。因此您不能将相应的数据映射到MPI结构中.最明显的原因是,从一个调用到下一个调用(或从一个进程调用到下一个调用),不能保证c
指向的结构地址和数据地址的偏移量相同(实际上,几乎可以保证它会不同)。因此您无法可靠地映射它们。
a
和b
(如果需要,可以创建一个MPI结构来传输它们的数组)。然后,您将转移c
指向的内存,该内存是您事先分配的。
您的代码可能变成例如:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType( MPI_Datatype* newType ) {
struct bar tmp[2];
MPI_Aint extent = &tmp[1] - &tmp[0];
MPI_Type_create_resized( MPI_2INT, 0, extent, newType );
MPI_Type_commit( newType );
}
int main( int argc, char* argv[] ) {
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &p );
int cLen = atoi( argv[1] );
MPI_Datatype Bar_type;
defineMPIType( &Bar_type );
struct bar msg;
msg.c = ( int* ) malloc( sizeof( int ) * cLen );
if ( rank == 0 ) {
msg.a = 1;
msg.b = 2;
for ( int i = 0; i < cLen; ++i ) {
msg.c[i] = i;
}
MPI_Send( &msg, 1, Bar_type, 1, 111, MPI_COMM_WORLD );
MPI_Send( msg.c, cLen, MPI_INT, 1, 222, MPI_COMM_WORLD );
}
else if ( rank == 1 ) {
MPI_Recv( &msg, 1, Bar_type, 0, 111, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
MPI_Recv( msg.c, cLen, MPI_INT, 0, 222, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
}
printf("Rank %d has a = %d, b = %d, c = [", rank, msg.a, msg.b );
for ( int i = 0; i < cLen - 1; ++i ) {
printf( "%d, ", msg.c[i] );
}
printf( "%d]
", msg.c[cLen - 1] );
free( msg.c );
MPI_Type_free( &Bar_type );
MPI_Finalize();
return 0;
}
这提供了:
$ mpirun -n 2 ./a.out 3
Rank 0 has a = 1, b = 2, c = [0, 1, 2]
Rank 1 has a = 1, b = 2, c = [0, 1, 2]
MPI编码快乐。
这篇关于为包含动态数组的结构创建MPI类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文