MPI中的非阻塞通信
前面已经介绍了阻塞通信和非阻塞通信的区别。下面我们介绍MPI中对非阻塞通信的支持,和通常的调用模式。
上面的四种通信模式都有对应的非阻塞通信模式。他们对应的函数如下:
标准通信模式: MPI_ISEND MPI_IRECV
缓冲通信模式: MPI_IBSEND
同步通信模式: MPI_ISSEND
就绪通信模式: MPI_IRSEND
和它们的阻塞方式相比,基本上只是由阻塞变为了非阻塞,其他的通信行为相同。
下面来看标准的非阻塞通信的函数。
MPI_ISEND( buf, count, datatype, dest, tag, comm, request )
IN buf
IN count
IN datatype
IN dest
IN tag
IN comm
OUT request 返回的非阻塞通信对象(用于TEST/WAIT使用)
int MPI_Isend( void* buf, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm, MPI_Request *request)
消息接收
MPI_IRECV( buf, count, datatype, source, tag, comm, request )
OUT buf
IN count
IN datatype
IN source
IN tag
IN comm
OUT request 返回的非阻塞通信对象(用于TEST/WAIT使用)
int MPI_Irecv( void *buf, int count, MPI_Datatype datatype, int
source
int tag, MPI_Comm comm, MPI_Request *request )
比较它们和MPI_SEND/MPI_RECV的形式,可以发现非阻塞通信对象多出了一个MPI_Request参数。这个参数是提供给后面的非阻塞通信检测/等待函数用的,它的意义很象文件操作中的文件句柄,它用来唯一的标识不同的非阻塞通信任务。
由于非阻塞通信在调用后不用等待通信完全结束就可以返回,所以非阻塞通信的返回并不意味着通信的完成。在返回后,用户还需要检测甚至等待通信的完成。MPI提供了下面的函数来完成这些目的。
功能描述(使用情形) 状态检测 等待完成
单个非阻塞通信调用 MPI_TEST MPI_WAIT
一组非阻塞通信中任意一个 MPI_TESTANY MPI_WAITANY
多个非阻塞通信 MPI_TESTSOME MPI_WAITSOME
所有非阻塞通信 MPI_TESTALL MPI_WAITALL
功能描述(使用情形)
|
状态检测
|
等待完成
|
单个非阻塞通信调用
|
MPI_TEST
|
MPI_WAIT
|
一组非阻塞通信中任意一个
|
MPI_TESTANY
|
MPI_WAITANY
|
多个非阻塞通信
|
MPI_TESTSOME
|
MPI_WAITSOME
|
所有非阻塞通信
|
MPI_TESTALL
|
MPI_WAITALL
|
其中TEST用来检测对应的非阻塞通信是否已经完成,注意,它只给出状态,而不会阻塞等待对应的非阻塞通信完成。而WAIT是一个阻塞调用,用来等待对应的非阻塞通信完成,只有当某些条件满足时,它才会退出。MPI_TEST的形式如下。
MPI_TEST( request, flag, status )
INOUT request 非阻塞通信对象
OUT flag 操作是否完成(标志变量)
OUT status 返回状态
int MPI_Test( MPI_Request *request, int *flag, MPI_Status *status
);
最简单的非阻塞通信模式。先看一个简单的ISEND的例子(来自于MPICH-1.2.3软件包所附的例子isendtest.c)。
// isendtest.c
#include <stdio.h>
#include "mpi.h"
#define SIZE 100
int main( int argc, char *argv[])
{
int num_procs,my_id,flag;
int buf[SIZE][SIZE];
MPI_Status status;
MPI_Request handle;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&num_procs);
MPI_Comm_rank(MPI_COMM_WORLD,&my_id);
//两个进程,进程1非阻塞发送
if ( my_id == 1 ) {
MPI_Isend (buf, SIZE*SIZE, MPI_INT, 0, 0, MPI_COMM_WORLD, &handle
);
flag = 0;
//采用循环等待的方法等待非阻塞发送的完成
while (flag == 0) {
MPI_Test (&handle, &flag, &status);
printf("%d Wait for completition flag = %d handle = %ld
....\n",
my_id, flag, (long) handle);
}
}
else if (my_id == 0 ) {
//进程0阻塞接收
MPI_Recv (buf, SIZE*SIZE, MPI_INT, 1, 0, MPI_COMM_WORLD, &status
);
}
printf("%d Done ....\n",my_id);
MPI_Finalize();
return 0;
}
MPI为非阻塞通信提供了非常丰富的函数调用,本文中不对具体的调用做更多的介绍,请参见MPI标准中相关的说明。
|