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标准中相关的说明。