前面已经介绍了阻塞通信和非阻塞通信的区别。下面我们介绍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标准中相关的说明。 |