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

4

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

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

我之前已经使用过此函数,用于不同的发送和接收缓冲区,其能正常工作。因此我确定其他参数没有问题。

在有2个进程的情况下,其中一个进程无法返回。当我将发送缓冲区复制到另一个 std::vector 时发生了这种情况。

vector <double> vel2;
vel2 = vel;

为什么使用vel2作为发送缓冲区后所有进程都返回了?

2个回答

8

一般而言,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来清楚地表示该参数被忽略。

3

从规格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,无法确定。

我假设缓冲区内存存在可能的竞争条件,如果存在这种情况,则行为未定义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接