在MPI中使用非阻塞通信确认消息接收

时间:2016-10-25 15:35:14

标签: c++ c fortran mpi

前提: 许多职级需要将数据发送到其他职级。其他职级是

1)通常是总沟通者规模的一小部分

2)接收方不知道

因此,接收方不知道他们将接收多少消息或从哪里接收消息。

可能的解决方案如下

Isend all messages

Busy wait
    Probe & Recv messages
    When all Isends complete
         start IBarrier
    exit when IBarrier completes

当自己的Isends完成时,每个等级都达到了障碍,当所有等级的出站消息“在空中”时,障碍就会结束

问题: MPI 3.1标准的3.7.3节规定,使用MPI_Test或MPI_Wait完成发送并不意味着相应的操作已经完成,而只是缓冲区可以自由重用。

这显然会导致竞争状态,其中有一个悬挂的Isend没有相应的Irecv。接收等级不再是侦听,因为在消息可以与Irecv匹配之前到达IBarrier。

1 个答案:

答案 0 :(得分:1)

从您揭露问题的方式来看,我认为开始时没有同步问题。因此,这是我建议的解决方案:

int sendSizes[size]; // size of the messages I'll send to each process
// Populate sendSizes here
/* ........ */

int recvSizes[size]; // size of the messages I'll receive from each process
MPI_Alltoall( sendSizes, 1, MPI_INT, recvSizes, 1, MPI_INT, MPI_COMM_WORLD );

// Now I know exactly what to expect from each process
// I could use a Irecv - Isend - Waitall approach
// but a MPI_Alltoallv might be more appropriated
int sendDispls[size], recvDispls[size];
sendDispls[0] = recvDispls[0] = 0;
for ( int i = 0; i < size - 1; i++ ) {
    sendDispls[i+1] = sendDispls[i] + sendSizes[i];
    recvDispls[i+1] = recvDispls[i] + recvSizes[i];
}
int fullSendSize = sendDispls[size-1] + sendSizes[size-1];
double sendBuff[fullSendSize];
// Populate the sending buffer here
/* ........ */

int fullRecvSize = recvDispls[size-1] + recvSizes[size-1];
double recvBuff[fullRecvSize];
MPI_Alltoallv( sendBuff, sendSizes, sendDispls, MPI_DOUBLE,
               recvBuff, recvSizes, recvDispls, MPI_DOUBLE,
               MPI_COMM_WORLD );

正如您所看到的,解决方案的基石是首先使用MPI_Alltoall()调用,让每个进程知道每个其他进程的期望。这种全局通信在进程同步方面不应成为问题,因为所有进程都应该在开始时进行同步。

一旦完成,最初的问题变得微不足道。只需使用MPI_Irecv()循环,然后是MPI_Isend()循环和最终MPI_Waitall()即可解决此问题。但是,我宁愿在这里调用MPI_Alltoallv()来做同样的事情,只是为了表明它也是可能的。简单地说,在现实生活中,发送和接收缓冲区可能已经存在,只需要计算位移以指向正确的位置,从而节省不必要的数据副本。

但同样,这一部分现在变得微不足道了,所以您可以在代码的上下文中看到最好的部分。