【问题标题】:Problem with using MPI_SENDRECV with 4 threads将 MPI_SENDRECV 与 4 个线程一起使用时出现问题
【发布时间】:2019-08-22 03:58:36
【问题描述】:

作为一个最小的问题,我试图在 4 个处理器之间发送一个整数:0 -> 3(等级0 发送到等级3 并从等级3 接收),2 -> 1, 1 -> 2, 3 -> 0。它永远不会完成执行并挂起,可能正在等待其他线程的响应。

我正在使用mpif90 ... 编译代码并使用mpiexec -np 4 ... 运行。下面是最小的 sn-p:

program sendrecv
  implicit none
  include "mpif.h"
  integer :: foo, bar
  integer :: mpi_rank, mpi_size, ierr
  integer :: mpi_sendto, mpi_recvfrom
  integer :: istat(MPI_STATUS_SIZE), status, i

  call MPI_INIT(ierr)
  call MPI_COMM_SIZE(MPI_COMM_WORLD, mpi_size, ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD, mpi_rank, ierr)
  print *, "SENDING..."

  if (mpi_rank .eq. 0) then
    mpi_sendto = 3; mpi_recvfrom = 3
  else if (mpi_rank .eq. 1) then
    mpi_sendto = 2; mpi_recvfrom = 2
  else if (mpi_rank .eq. 2) then
    mpi_sendto = 1; mpi_recvfrom = 1
  else
    mpi_sendto = 0; mpi_recvfrom = 0
  end if

  foo = mpi_rank
  do i = 1, 5
    foo = mpi_rank
    call MPI_SENDRECV(foo, 1,&
                    & MPI_INTEGER, mpi_sendto, mpi_rank * 10 + i,&
                    & bar, 1,&
                    & MPI_INTEGER, mpi_recvfrom, mpi_rank * 10 + i,&
                    & MPI_COMM_WORLD, istat, ierr)
  end do

  print *, "...DONE"
  call MPI_FINALIZE(ierr)
end

我真的不明白为什么这个程序会挂起,也许我错过了什么或做错了什么。如果我理解正确,MPI_SENDRECV 只是非阻塞sendrecv 有两个wait-s。在这种情况下,假设rank=0 发送到rank=3 接收它应该没有任何问题,对吧?

我尝试从不同的线程发送/接收,即这样做:

  if (mpi_rank .eq. 0) then
    mpi_sendto = 1; mpi_recvfrom = 3
  else if (mpi_rank .eq. 1) then
    mpi_sendto = 2; mpi_recvfrom = 0
  else if (mpi_rank .eq. 2) then
    mpi_sendto = 3; mpi_recvfrom = 1
  else
    mpi_sendto = 0; mpi_recvfrom = 2
  end if

还是不行。

UPD 正如所指出的,在执行SENDRECV 时标签应该相同,但是如果在循环中执行此调用,类似的标签并没有多大帮助(请参阅修改后的代码)。旧版本:

call MPI_SENDRECV(foo, 1,&
                    & MPI_INTEGER, mpi_sendto, 200,&
                    & bar, 1,&
                    & MPI_INTEGER, mpi_recvfrom, 100,&
                    & MPI_COMM_WORLD, status, ierr)

UPD#2 实际上,如果有人感兴趣,我找到了一个discussion,这正是我遇到的关于为什么SENDRECV-s 有时可能会死锁的问题。

【问题讨论】:

    标签: parallel-processing fortran mpi


    【解决方案1】:

    这里的“线程”一词有误导性,你应该谈论 MPI 任务或 MPI 进程(两者是等价的)。

    根本原因是标签不匹配。您使用标签200 发送,但使用标签100 接收。

    另外,您应该使用istat 而不是status 作为MPI_Sendrecv() 的状态参数。

    以下是修复程序的方法

    call MPI_SENDRECV(foo, 1,&
                    & MPI_INTEGER, mpi_sendto, 200,&
                    & bar, 1,&
                    & MPI_INTEGER, mpi_recvfrom, 200,&
                    & MPI_COMM_WORLD, istat, ierr)
    

    【讨论】:

    • 确实如此,谢谢!抱歉,我实际上想到了来自循环内的SENDRECV 调用。在那种情况下,相同的标签似乎不起作用。 :\
    • 好的,nvm。我发现了问题。这是status 的大小,它可能会溢出MPI_STATUS_SIZE 并修改它不应该在SENDRECV 调用中的其他变量。使用istat 有效。谢谢!混蛋编译器甚至懒得警告我:\
    • 如果您使用use mpi 而不是include 'mpif.h',您更有可能收到此类警告。 use mpi_f08 更好(但需要一些编译器支持,并且可能还需要一些代码更改)。
    猜你喜欢
    • 2011-03-15
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2010-10-26
    • 2020-06-17
    • 1970-01-01
    相关资源
    最近更新 更多