gpt4 book ai didi

c - 使用 MPI (C) 交换 halo/ghost 单元格时出现未知错误

转载 作者:太空宇宙 更新时间:2023-11-04 06:35:26 24 4
gpt4 key购买 nike

我是 MPI 的新手,所以请放轻松……无论如何,我正在尝试使用 MPI_Isend 和 MPI_Irecv 进行非阻塞通信。我写了一个名为“halo_exchange”的子程序,每次我需要在相邻子域之间交换光环单元时我都想调用它。我能够正确地划分域,并且我知道我的每个邻居等级。在下面的代码中,邻居是面向北/南的(即我使用一维行分解)。所有过程都用于计算。也就是说,所有进程都会调用这个子程序,需要交换数据。

最初我对北边界和南边界使用了一组 MPI_Isend/MPI_Irecv 调用,但后来我将其拆分,认为将“MPI_PROC_NULL”传递给函数可能有问题(边界不是周期性的)。这就是 if 语句的原因。代码继续卡在“MPI_Waitall”语句上,我不知道为什么?它实际上只是在等待,我不确定它在等待什么?

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

//---------------------------------------------------------------------------------------
// FUNCTION "halo_exchange"
//---------------------------------------------------------------------------------------
void halo_exchange(PREFIX **array, MPI_Comm topology_comm, \
int nn, int S_neighbor, int N_neighbor)
{
int halo = 2;
int M = 20;

...

double *S_Recv,*N_Recv;
double *S_Send,*N_Send;

// Receive buffers
S_Recv = (double *) calloc( M*halo,sizeof(double) );
N_Recv = (double *) calloc( M*halo,sizeof(double) );

// Send buffers
S_Send = (double *) calloc( M*halo,sizeof(double) );
N_Send = (double *) calloc( M*halo,sizeof(double) );

...
// send buffers filled with data
// recv buffers filled with zeros (is this ok...or do I need to use malloc?)
...

if (S_neighbor == MPI_PROC_NULL)
{
MPI_Status status[2];
MPI_Request req[2];

MPI_Isend(&N_Send,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[0]);
MPI_Irecv(&N_Recv,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[1]);
...
...
MPI_Waitall(2,req,status);

}
else if (N_neighbor == MPI_PROC_NULL)
{
MPI_Status status[2];
MPI_Request req[2];

MPI_Isend(&S_Send,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[0]);
MPI_Irecv(&S_Recv,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[1]);
...
...
MPI_Waitall(2,req,status);

}
else
{
MPI_Status status[4];
MPI_Request req[4];

MPI_Isend(&S_Send,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[0]);
MPI_Isend(&N_Send,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[1]);

MPI_Irecv(&N_Recv,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[2]);
MPI_Irecv(&S_Recv,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[3]);
...
...
MPI_Waitall(4,req,status);

}
...
}

这是我最初的理解,显然缺少一些东西:由于每个进程都调用这个子程序,所以所有的发送/接收函数都会被调用。然后所有进程将在它们的 MPI_Waitall 点等待相应的通信发生。当他们完成后,它继续前进……有人能告诉我为什么我的不动吗???另外,我对“标签”参数不太清楚(线索?)感谢您提前提供的所有帮助!!!

最佳答案

这段代码

  MPI_Status status[4];
MPI_Request req[4];

MPI_Isend(&S_Send,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[0]);
MPI_Isend(&N_Send,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[1]);

MPI_Irecv(&N_Recv,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[2]);
MPI_Irecv(&S_Recv,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[3]);
...
...
MPI_Waitall(4,req,status);

大部分都很好,您不必在 MPI_PROC_NULL 邻居周围 if;这就是 MPI_PROC_NULL 的用途,这样您就可以将极端情况插入 MPI 例程本身,从而大大简化面向开发人员的通信代码。

这里的问题实际上是标签。标签附加到各个消息。标签可以是任何不超过某个最大值的非负整数,但关键是发送方和接收方必须就标签达成一致。

如果您向您的北邻居发送一些带有标记 2 的数据,那很好,但现在假装您是北邻居;您将收到来自南边邻居的相同消息,标签为 2。同样,如果您要发送带有标签 1 的南邻居数据,南邻居将需要从带有标签 1 的北邻居接收数据。

所以你真的想要

  MPI_Isend(&S_Send,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[0]);
MPI_Isend(&N_Send,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[1]);

MPI_Irecv(&N_Recv,halo*M,MPI_DOUBLE,N_neighbor,1,topology_comm,&req[2]);
MPI_Irecv(&S_Recv,halo*M,MPI_DOUBLE,S_neighbor,2,topology_comm,&req[3]);

根据以下 OP 评论更新:

事实上,因为 S_Recv 等已经是指向数据的指针,如:

  S_Recv = (double *) calloc( M*halo,sizeof(double) );

你真正想要的是:

  MPI_Isend(S_Send,halo*M,MPI_DOUBLE,S_neighbor,1,topology_comm,&req[0]);
MPI_Isend(N_Send,halo*M,MPI_DOUBLE,N_neighbor,2,topology_comm,&req[1]);

MPI_Irecv(N_Recv,halo*M,MPI_DOUBLE,N_neighbor,1,topology_comm,&req[2]);
MPI_Irecv(S_Recv,halo*M,MPI_DOUBLE,S_neighbor,2,topology_comm,&req[3]);

关于c - 使用 MPI (C) 交换 halo/ghost 单元格时出现未知错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15587221/

24 4 0