MPI无法通过MPI_Send和MPI_Recv向自己发送数据

bxs*_*shi 2 mpi openmpi

我正在尝试实施MPI_Bcast,并且我计划通过MPI_SendMPI_Recv似乎我无法向自己发送消息?

代码如下

void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) {
     int comm_rank, comm_size, i;
     MPI_Comm_rank(comm, &comm_rank);
     MPI_Comm_size(comm, &comm_size);
     if(comm_rank==root){
         for(i = 0; i < comm_size; i++){
                 MPI_Send(buffer, count, datatype, i, 0, comm);
         }
     }
     MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);
  }
Run Code Online (Sandbox Code Playgroud)

对此有什么建议吗?或者我不应该向自己发送消息而只是进行内存复制?

Hri*_*iev 6

你的程序在多个层面上都是错误的。首先,条件语句有一个错误:

if(comm_rank=root){
Run Code Online (Sandbox Code Playgroud)

这不是比较comm_rank而是root分配rootcomm_rank,然后循环仅在root非零时才执行,此外它会由所有等级执行。

其次,根进程不需要向自身发送数据,因为数据已经存在。即使您想发送和接收,您也应该注意到两者MPI_SendMPI_Recv仔细阅读相同的缓冲区空间,这是不正确的。一些 MPI 实现使用直接内存复制进行自交互,即库可能用来memcpy()传输消息。使用memcpy()重叠缓冲区(包括使用相同的缓冲区)会导致未定义的行为。

实现线性广播的正确方法是:

void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)
{
   int comm_rank, comm_size, i;
   MPI_Comm_rank(comm, &comm_rank);
   MPI_Comm_size(comm, &comm_size);
   if (comm_rank == root)
   {
      for (i = 0; i < comm_size; i++)
      {
         if (i != comm_rank)
            MPI_Send(buffer, count, datatype, i, 0, comm);
      }
   }
   else
      MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);
}
Run Code Online (Sandbox Code Playgroud)

进程与自身对话而不发生死锁的通常方法是:

  • MPI_Isend使用和 的组合或和MPI_Recv的组合;MPI_SendMPI_Irecv
  • 使用缓冲发送MPI_Bsend
  • 使用MPI_SendrecvMPI_Sendrecv_replace.

在像您这样在循环中完成多个发送的情况下,MPI_Irecv和 的组合效果很好。MPI_Send例如:

MPI_Request req;

// Start a non-blocking receive
MPI_Irecv(buff2, count, datatype, root, 0, comm, &req);
// Send to everyone
for (i = 0; i < comm_size; i++)
   MPI_Send(buff1, count, datatype, i, 0, comm);
// Complete the non-blocking receive
MPI_Wait(&req, MPI_STATUS_IGNORE);
Run Code Online (Sandbox Code Playgroud)

请注意发送和接收使用单独的缓冲区。可能唯一允许将同一缓冲区用于发送和接收的点对点 MPI 通信调用以及MPI_Sendrecv_replace集体 MPI 调用的就地模式。但这些是在内部以这样的方式实现的,即同一存储区域不会同时用于发送和接收。