c++ - 在 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

通过让每个等级在其自己的 Isends 完成时到达屏障,屏障在所有等级上的出站消息“在空中”时结束

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

这显然会导致一个竞争条件,即有一个挂起的 Isend 没有对应的 Irecv。接收级别不再监听,因为在消息可以与 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 );

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

一旦完成,最初的问题就变得微不足道了。它可以通过使用 MPI_Irecv() 循环,然后是 MPI_Isend() 循环和最后的 MPI_Waitall() 来解决。然而,我宁愿在这里调用 MPI_Alltoallv() 来做同样的事情,只是为了证明它也是可能的。简而言之,在现实生活中,发送和接收缓冲区可能已经存在,只需要计算位移以指向正确的位置,从而避免不必要的数据拷贝。

但同样,这部分现在很简单,因此您可以自行决定在您的代码上下文中什么是最好的。

关于c++ - 在 MPI 中使用非阻塞通信确认消息接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40244097/

相关文章:

c++ - G++ 无法找到对 raw() 或 cbreak() 的引用,即使在链接 curses 时也是如此

c++ - `synonym` 中的 `typedef` 是强制性的吗?

c++ - 编译具有相同 header 的 C 和 C++ 文件时 undefined reference

documentation - Fortran 函数、模块和子例程的自动文档

fortran - 使用接口(interface)和可分配的 WORK 数组的 Lapack 例程 SGELS 中出现错误

c++ - 在 GoogleTest 中使用 ASSERT 和 EXPECT

c - 使用最大的账单代表金额。指针困惑

c - 如何摆脱角色以获得所需的输出

c - 混合编程发布失败但调试成功

c++ - 如何使用 C++ 为 tensorflow 加载检查点和推理?