C++ 通过MPI中的非阻塞通信确认消息接收

C++ 通过MPI中的非阻塞通信确认消息接收,c++,c,fortran,mpi,C++,C,Fortran,Mpi,前提: 许多列组需要向其他列组发送数据。其他级别是 1) 通常为通信器总尺寸的一小部分 2) 接收者不知道 因此,接收者不知道他们将接收多少消息,也不知道从哪里接收 一个可能的解决办法如下 Isend all messages Busy wait Probe & Recv messages When all Isends complete start IBarrier exit when IBarrier completes 通过让每个列组在

前提: 许多列组需要向其他列组发送数据。其他级别是

1) 通常为通信器总尺寸的一小部分

2) 接收者不知道

因此,接收者不知道他们将接收多少消息,也不知道从哪里接收

一个可能的解决办法如下

Isend all messages

Busy wait
    Probe & Recv messages
    When all Isends complete
         start IBarrier
    exit when IBarrier completes
通过让每个列组在其自己的iSend完成时到达屏障,当所有列组上的出站消息都“在空中”时屏障完成

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


这显然导致了一种竞争条件,即存在一个没有相应Irecv的挂起Isend。接收列组不再侦听,因为在消息可以与Irecv匹配之前已到达IBarrier。

从您暴露问题的方式来看,在我看来,一开始没有同步问题。因此,我建议的解决办法如下:

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 );
int sendSizes[size];//我将发送到每个进程的消息的大小
//在此处填充SendSize
/* ........ */
int recvSizes[大小];//我将从每个进程接收的消息的大小
MPI_all ToAll(发送大小,1,MPI_INT,recvSizes,1,MPI_INT,MPI_COMM_WORLD);
//现在我确切地知道了每个过程的期望
//我可以使用Irecv-Isend-Waitall方法
//但MPI_Alltoallv可能更合适
int senddpress[size],recvDispls[size];
senddephs[0]=recvDispls[0]=0;
对于(int i=0;i
正如您所看到的,解决方案的基础是首先使用对
MPI\u Alltoall()
的调用,让每个进程都知道从其他进程中可以得到什么。就进程同步而言,这种全局通信不应该是一个问题,因为所有进程都应该在启动时同步

一旦这样做了,最初的问题就变得微不足道了。只需使用
MPI\u-Irecv()
循环,然后是
MPI\u-Isend()
循环和最终的
MPI\u-Waitall()
即可解决此问题。然而,我在这里使用了一个调用
MPI\u Alltoallv()
来做同样的事情,只是为了说明这也是可能的。简单地说,在现实生活中,发送和接收缓冲区可能已经存在,并且只需要计算位移以指向正确的位置,从而节省不必要的数据副本


但是,这一部分现在又变得微不足道了,因此您需要看看在代码上下文中什么是最好的。

一个(发送消息完成)与另一个(知道何时停止接收)有什么关系?对于第一种,您可以使用
MPI\u Issend
synchronous mode send,正如您引用的部分所解释的。对于第二种情况,发送一条停止消息(例如,由一个特殊标记指示)。没有一个排名第一的人知道1)是否所有消息都发送到特定的排名2)有多少消息。在单个列组的所有消息被发送(到不同的目的地)后到达一个屏障似乎是一种很好的同步方式:一旦屏障完成,所有列组上的所有消息都已到达各自的recvMPI 3.2?这是否存在?我知道的最后一个是3.1,但也许我错过了什么。。。除此之外,我不明白你的问题。你能举例说明一段有意义的代码吗?对不起,你是对的。我一定是错过了版本号。另外,我将对问题进行编辑,使其更清楚。这是相关的