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

Same send and receive buffers in MPI

本文关键字:缓冲区 MPI      更新时间:2023-10-16

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

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

我以前在不同的发送和接收缓冲区中将此函数用于其他目的,它起到了作用。这就是为什么我确信其他参数没有问题。

在两个进程的情况下,其中一个进程不会返回。当我将发送缓冲区复制到另一个std::vector

vector <double> vel2;
vel2 = vel;

并使用CCD_ 3作为发送缓冲区,然后所有进程返回。为什么?

一般来说,MPI要求参数没有别名。本标准第2.3章明确提到了这一点。

除非另有规定,否则类型为OUT或类型为INOUT的参数不能与传递给MPI过程的任何其他参数别名。

这解释了代码出现问题的原因。然而,有可能非常容易地解决您的问题,而不必显式地复制您的缓冲区:MPI_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来明确参数被忽略。

来自规范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的了解还不足以确定。

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