MPI 中相同的发送和接收缓冲区

Same send and receive buffers in MPI

在我的代码中,每个进程都在数组的特定部分上工作。我希望每个进程将其处理的部分发送到其他进程并从其他进程接收其他部分。为此,我使用了 MPI_Allgatherv 但我保持发送和接收缓冲区相同:

MPI_Allgatherv (&vel[0],  localSizesFaceV[rank], MPI_DOUBLE, &vel[0],  localSizesFaceV, displsFaceV, MPI_DOUBLE, MPI_COMM_WORLD);

我之前将此函数用于其他目的,使用不同的发送和接收缓冲区,并且它有效。这就是为什么我确定其他参数没有问题的原因。

在2个进程的情况下,其中一个进程没有return。当我将发送缓冲区复制到另一个 std::vector

vector <double> vel2;
vel2 = vel;

并使用 vel2 作为发送缓冲区,然后所有进程 returned。为什么?

来自规范 http://www.mpich.org/static/docs/v3.1/www3/MPI_Allgatherv.html

int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
               void *recvbuf, const int *recvcounts, const int *displs,
               MPI_Datatype recvtype, MPI_Comm comm)

sendbuf 是常量,但您还传递了一个指针,允许通过 recvbuf 更改 sendbuf 底层内存。这看起来有风险,但我对 MPI 的了解还不足以确定。

我还假设缓冲内存上可能存在竞争条件,如果是这样 - 这是未定义的行为。

一般来说,MPI 要求参数没有别名。这是明确提到的 chapter 2.3 of the current standard.

Unless specified otherwise, an argument of type OUT or type INOUT cannot be aliased with any other argument passed to an MPI procedure.

这解释了为什么你的代码有问题。但是,有可能很容易地解决您的问题,而不必显式复制您的缓冲区:MPI_IN_PLACE 关键字。它指定通信将 "in-place" 在相关的地方也使用输出缓冲区作为输入缓冲区来完成。

您的代码将变为:

MPI_Allgatherv( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &vel[0],  localSizesFaceV, displsFaceV, MPI_DOUBLE, MPI_COMM_WORLD);

注意:用于发送缓冲区的实际类型无关紧要。如果你愿意,你可以保留 MPI_DOUBLE,但我倾向于使用 MPI_DATATYPE_NULL 来表明该参数被忽略。