新类型的构造和使用
通常情况下,新类型的构造和使用由下面几个过程(依次)组成:
1. 新类型的构造(通过调用构造器)
2. 新类型的提交(调用MPI_TYPE_COMMIT)
3. 新类型的使用(发送,接收消息等等)
4. 新类型的释放(调用MPI_TYPE_FREE)
提交新类型的调用形式如下:
MPI_TYPE_COMMIT( datatype )
INOUT datatype
int MPI_Type_commit( MPI_Datatype *datatype );
一旦一个新的数据类型经过提交,用户可以在程序中向使用预定义类型一样的使用它们,这也使用户可以在自己定义的派生数据类型的基础上,再定义更为复杂的新的类型。
释放新类型的调用形式如下:
MPI_TYPE_FREE( datatype )
INOUT datatype
int MPI_Type_free( MPI_Datatype *datatype );
打包和解包
打包(pack)和解包(unpack)为用户提供了发送不连续数据又一种方法。基本原理是在发送前先把数据包装(拷贝)到一个连续的(发送)缓冲区,数据到达后再从(连续得接收)缓冲区内把数据取出来(解包)。
与打包/解包操作有关的函数调用如下。
打包操作
MPI_PACK( inbuf, incount, datatype, outbuf, outcount, position,
comm )
IN inbuf 输入缓冲区起始地址(需要打包的数据)
IN incount 输入数据的数目
IN datatype 输入数据的类型
OUT outbuf 输出缓冲区起始地址(打包后的数据)
IN outcount 输出缓冲区的长度
INOUT position 输出缓冲区当前打包位置
IN comm 通信域
int MPI_Pack( void *inbuf, int incount, MPI_Datatype datatype,
void *outbuf, int outcount, int *position, MPI_Comm comm );
需要指出的是,一个完整的打包过程通常包括连续多次对MPI_PACK的调用。
解包操作
MPI_UNPACK( inbuf, insize, position, outbuf, outcount, datatype,
comm )
IN inbuf 输入缓冲区起始地址(需要解包的数据)
IN insize 输入数据的数目
INOUT position 输入缓冲区当前解包位置
OUT outbuf 输出缓冲区起始地址(打包后的数据)
IN outcount 输出缓冲区的长度
IN datatype 输出数据的类型
IN comm 通信域
int MPI_Unpack( void *inbuf, int insize, int *position, void
*outbuf,
int outcount, MPI_Datatype datatype,MPI_Comm comm );
需要指出的是,一个完整的解包过程也通常包括连续多次对MPI_UNPACK的调用。
计算打包所需的空间
MPI_PACK_SIZE( incount, datatype, comm, size )
IN incount 给定数据类型的数目
IN datatype 数据类型
IN comm 通信域
OUT size 以字节为单位的incount个datatype类型数据打包所需要的空间
int MPI_Pack_size( int incount, MPI_Datatype datatype, MPI_Comm
comm,
int *size );
注意size返回的是一个上界,因为打包空间可能会依赖于上下文(比如第一个打包单元需要更多的空间)。
下面是一个完整的打包和解包的例子(在都志辉等所著的《高性能计算并行编程技术--MPI并行程序设计》中的173页给出)。
#include <stdio.h>
#include "mpi.h"
int main( int argc, char **argv) {
int rank, packsize, position;
int a;
double b;
char packbuf[100];
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
if( rank == 0 ) {
// 进程0读数据
scanf( "%d%lf", &a, &b );
packsize = 0;
MPI_Pack( &a, 1, MPI_INT, packbuf, 100, &packsize,
MPI_COMM_WORLD );
MPI_Pack( &b, 1, MPI_DOUBLE, packbuf, 100, &packsize,
MPI_COMM_WORLD );
}
//
MPI_Bcast( &packsize, 1, MPI_INT, 0, MPI_COMM_WORLD );
//
MPI_Bcast( packbuf, packsize, MPI_PACKED, 0, MPI_COMM_WORLD );
if( rank != 0 ) {
position = 0;
MPI_Unpack( packbuf, packsize, &position, &a, 1, MPI_INT,
MPI_COMM_WORLD );
MPI_Unpack( packbuf, packsize, &position, &b, 1, MPI_DOUBLE,
MPI_COMM_WORLD );
}
printf( "Process %d got %d and %lf
\n", rank , a, b );
MPI_Finalize( );
return 0;
}
|