MPI - 在使用 MPI_Probe() 时发送我自己的结构
Posted
技术标签:
【中文标题】MPI - 在使用 MPI_Probe() 时发送我自己的结构【英文标题】:MPI - send my own structure while using MPI_Probe() 【发布时间】:2015-02-22 16:02:32 【问题描述】:我需要使用 MPI_Send() 发送我自己的结构。问题是,我不确定如何正确使用 MPI 中的结构。当然我也试过自己找,但是没有找到完全符合我需求的例子。
现在,当我运行 Makefile 时,我得到了这个错误:
probe_and_struct.c: In function ‘main’:
probe_and_struct.c:72:13: error: expected ‘;’ before ‘buf’
myStruct buf;
^
probe_and_struct.c:73:4: error: ‘buf’ undeclared (first use in this function)
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
^
probe_and_struct.c:73:4: note: each undeclared identifier is reported only once for each function it appears in
probe_and_struct.c:73:21: error: expected expression before ‘)’ token
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
^
make: *** [probe_and_struct] Error 1
那么,你能告诉我,我做错了什么,我应该如何正确使用这个结构?
编辑: 我已经重写了代码,但现在程序在 MPI_Send() 上因 Segmentation fault 而崩溃。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define ARR_LEN 2 // length of test array and the size sent
int main()
//---------------------------------------------------------------------------------------------------------------------------------------
// Create own structure
//----------------------
// Structure of structure :-)
struct
int id;
char c;
value;
// Declare parts of structure
MPI_Datatype myStruct;
int blockLengths[2];
MPI_Aint indices[2];
MPI_Datatype types[2];
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
//---------------------------------------------------------------------------------------------------------------------------------------
// Message passing
//-----------------
MPI_Init(NULL, NULL);
value.id = 0;
value.c = 'a';
// Number of processes, ID of current process
int world_size;
MPI_Comm_size( MPI_COMM_WORLD, &world_size );
int world_rank;
MPI_Comm_rank( MPI_COMM_WORLD, &world_rank );
// Test array to send
int arr[ 2 ] = 10,20;
MPI_Status status;
switch( world_rank )
case 0:
printf("This is the process number %d.\n\t", world_rank);
MPI_Send( &value, 2, myStruct, 1, 0, MPI_COMM_WORLD);
printf("The array of INT was sent.\n");
break;
case 1:
// Recognize the size of the message
MPI_Probe( 0, 0, MPI_COMM_WORLD, &status );
// Number of blocks sent
int status_size;
MPI_Get_count( &status, myStruct, &status_size );
// Allocate buffer with the size needed
myStruct buf;
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
// Receive and print message
MPI_Recv( buf, status_size, myStruct, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
printf("This is the process number %d.\n\t[ ", world_rank);
for( int i = 0; i < status_size; i++ )
printf( "%d ", buf[i] );
printf("]\n");
break;
default:
printf("This is the process number %d.\n", world_rank);
break;
MPI_Type_free( &myStruct );
MPI_Finalize();
return 0;
生成文件:
CC=mpicc
STD=-std=c11
all: probe_and_struct
probe_and_struct: probe_and_struct.c
$(CC) -o probe_and_struct probe_and_struct.c $(STD)
clean:
rm -f probe_and_struct
我的代码 - 第二版:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define ARR_LEN 2 // length of test array and the size sent
int main()
MPI_Init(NULL, NULL);
//---------------------------------------------------------------------------------------------------------------------------------------
// Create own structure
//----------------------
// Structure of structure :-)
typedef struct Values
int id;
char c;
Values;
Values value;
// Declare parts of structure
MPI_Datatype myStruct;
int blockLengths[2];
MPI_Aint indices[2];
MPI_Datatype types[2];
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
//---------------------------------------------------------------------------------------------------------------------------------------
// Message passing
//-----------------
value.id = 0;
value.c = 'a';
// Number of processes, ID of current process
int world_size;
MPI_Comm_size( MPI_COMM_WORLD, &world_size );
int world_rank;
MPI_Comm_rank( MPI_COMM_WORLD, &world_rank );
// Test array to send
//int arr[ 2 ] = 10,20;
MPI_Status status;
switch( world_rank )
case 0:
printf("Toto je proces cislo %d.\n\t", world_rank);
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
printf("Odeslano pole INTu.\n");
break;
case 1:
// Recognize the size of the message
MPI_Probe( 0, 0, MPI_COMM_WORLD, &status );
// Number of blocks sent
int status_size;
MPI_Get_count( &status, myStruct, &status_size );
puts("b");
// Allocate buffer with the size needed
Values * buf;
buf = (Values *) malloc( sizeof(Values) * status_size );
puts("b");
// Receive and print message
//MPI_Recv( buf, status_size, myStruct, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
printf("Toto je proces cislo %d.\n\t[ ", world_rank);
for( int i = 0; i < status_size; i++ )
printf( "%d %c", buf[i].id, buf[i].c );
printf("]\n");
break;
default:
printf("Toto je proces cislo %d.\n", world_rank);
break;
MPI_Type_free( &myStruct );
MPI_Finalize();
return 0;
【问题讨论】:
这一行:MPI_Datatype myStruct;只是创建一个 MPI_Datatype 的实例,而不是一个结构定义。 【参考方案1】:您将myStruct
用作类型并尝试实例化buf
,但myStruct
是MPI_Datatype
的实例(而不是类型)。
这部分代码(myStruct
被声明为MPI_Datatype
):
// Declare parts of structure
MPI_Datatype myStruct;
与这部分冲突(您尝试使用 myStruct
作为类型):
// Allocate buffer with the size needed
myStruct buf;
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
【讨论】:
好的,我明白了。但是,如果我需要一个缓冲区并且我需要它来存储我自己类型(结构)的数据,我应该怎么做呢? 这个链接应该让你开始如何创建自己的自定义结构:tutorialspoint.com/cprogramming/c_typedef.htm 非常感谢 - 现在我已经重写了代码,但是 Segmentation fault 是新错误 :-) - 在主要描述中【参考方案2】:您将MPI_type
与变量的类型混淆了。例如,让我们使用一个简单的int
。 int
的 MPI_type
是 MPI_INT
,对吗?但这不是正确的代码:
MPI_INT a = 5; //wrong, MPI_INT is an MPI_Type
//not the type we want to declare a variable
MPI_Send(&a, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
相反,你会使用:
int a = 5; //int is used to declare a variable
MPI_Send(&a, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); //MPI_INT is the type to
//send the variable
同样,如果你有一个结构为:
struct value
int id;
char c;
;
然后,在您使用MPI_Type_commit
声明一个新的 MPI 类型之后,您将使用:
struct value a = 4, 'b'; //struct value is used to declare the variable
MPI_Send(&a, 1, myStruct, 1, 0, MPI_COMM_WORLD); //myStruct is the MPI_Type used to
//send the variable
【讨论】:
【参考方案3】:您没有正确构建 MPI 数据类型。或者更确切地说,您在发送结构时没有正确使用构造的数据类型。您应该执行以下任一操作:
1。修复数据类型内部的偏移量
这段代码:
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
...
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
应该变成:
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Convert the absolute addresses into offsets
indices[1] -= indices[0];
indices[0] = 0;
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
...
MPI_Send( &value, 1, myStruct, 1, 0, MPI_COMM_WORLD);
此外,如果您愿意发送此类数据类型的数组,则应采取一些特殊措施来考虑编译器所做的类型填充。请参阅this question 如何。
2。发送数据时使用 MPI_BOTTOM
您可以保留绝对地址,而不是修复类型描述中的偏移量。缺点是使用绝对地址时,您只能发送构造数据类型时使用的特定变量 的内容(因为其他变量通常会在内存中的其他位置结束)。使用此类数据类型时,不指定缓冲区的地址,而是指定MPI_BOTTOM
,即此代码:
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
变成:
MPI_Send( MPI_BOTTOM, 1, myStruct, 1, 0, MPI_COMM_WORLD);
注意,在这种情况下,要发送的元素数量必须等于1
,即不能发送数组(除非数据类型本身描述了数组的所有元素) .
还要注意,在这两种情况下sizeof(struct Values)
都是错误的,必须将其更正为1
,因为MPI_Send
的第二个参数给出了要发送的元素数量,并且每个元素的实际数据大小已经编码在 MPI 数据类型中。
我强烈建议您使用选项 #1。
【讨论】:
以上是关于MPI - 在使用 MPI_Probe() 时发送我自己的结构的主要内容,如果未能解决你的问题,请参考以下文章
用于未知消息大小的 MPI 非阻塞发送和接收以及 mpi_iprobe()
使用 MPI_Type_create_subarray 发送时可以转置数组吗?