在我的代码中,每个进程都在数组的某个部分上运行。我希望每个进程将其处理的部分发送到其他进程,并从其他进程接收其他部分。为此,我使用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
作为发送缓冲区,然后返回所有进程。为什么呢?
答案 0 :(得分:6)
一般来说,MPI要求参数不带别名。明确提到chapter 2.3 of the current standard。
除非另有说明,否则为OUT类型的参数或类型INOUT 不能与传递给MPI过程的任何其他参数别名。
这解释了为什么您的代码有问题。但是,有可能非常轻松地解决您的问题,而无需显式复制缓冲区:MPI_IN_PLACE
关键字。它指定在任何相关的地方使用输出缓冲区作为输入缓冲区“就地”完成通信。
您的代码将变为:
MPI_Allgatherv( MPI_IN_PLACE, 0, MPI_TYPE_NULL, &vel[0], localSizesFaceV, displsFaceV, MPI_DOUBLE, MPI_COMM_WORLD);
注意:用于发送缓冲区的实际类型无关紧要。如果您愿意,可以保留MPI_DOUBLE
,但我倾向于使用MPI_TYPE_NULL
来明确该参数被忽略。
答案 1 :(得分:2)
来自规范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
是const,但您也传递了一个指针,允许通过sendbuf
更改recvbuf
底层内存。这看起来很危险,但我不太了解MPI。
我还假设缓冲存储器上存在可能的竞争条件,如果是这样 - 这是未定义的行为。