没有出现明显的僵局情况

  • 本文关键字:僵局 情况 mpi deadlock
  • 更新时间 :
  • 英文 :


我完全被卡住了。此代码

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if(myrank==0) i=1;
if(myrank==1) i=0;
MPI_Send(sendbuf, 1, MPI_INT, i, 99, MPI_COMM_WORLD);
MPI_Recv(recvbuf, 1, MPI_INT, i, 99, MPI_COMM_WORLD,&status);

确实在两个进程上运行。为什么没有僵局?与非阻塞版本相同

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if(myrank==0) i=1;
if(myrank==1) i=0;
MPI_Isend(sendbuf, 1, MPI_INT, i, 99, MPI_COMM_WORLD,&req);
MPI_Wait(&req, &status);
MPI_Irecv(recvbuf, 1, MPI_INT, i, 99, MPI_COMM_WORLD,&req);
MPI_Wait(&req, &status);

从逻辑上讲,应该有一个阻塞,但事实并非如此。为什么?如何强制MPI进行阻塞?

MPI有两种点对点操作-阻塞和非阻塞。最初这可能有点令人困惑,尤其是在发送消息时,但阻塞行为与物理数据传输操作无关。它与MPI可能仍然访问缓冲区(发送或接收(的时间段有关,因此应用程序不应该修改其内容(使用发送操作(,也可能仍然读取旧垃圾(使用读取操作(。

当您对MPI进行阻塞调用时,它只有在使用完发送或接收缓冲区时才会返回。对于接收操作,这意味着消息已被接收并存储在缓冲区中,但对于发送操作,情况会更加复杂。发送操作有几种模式:

  • buffed--数据不会立即发送,而是复制到本地用户提供的缓冲区,然后调用立即返回。实际的消息传输发生在将来某个时候,当MPI决定这样做时。有一个特殊的MPI调用MPI_Bsend,它总是以这种方式进行。此外,还需要附加和分离用户提供的缓冲区
  • synchronous—MPI等待,直到发布匹配的接收操作并且数据传输正在进行。一旦整个消息在传输过程中并且发送缓冲区可以自由重用,它就会返回。有一个特殊的MPI调用MPI_Ssend,它总是以这种方式运行
  • ready——MPI尝试发送消息,只有在已经发布了接收操作的情况下才会成功。这里的想法是跳过列之间的握手,这可能会减少延迟,但如果接收器没有准备好,具体会发生什么还没有确定。有一个特殊的调用MPI_Rsend,但建议不要使用它,除非你真的知道自己在做什么

MPI_Send调用所谓的标准发送模式,它可以是同步模式和缓冲模式的任何组合,后者使用MPI系统提供的缓冲区,而不是用户提供的缓冲。实际的细节留给MPI实现,因此差异很大。

最常见的情况是,小消息被缓冲,而大消息被同步发送,这就是你在案例中观察到的,但人们永远不应该依赖这种行为和";"小";随着实施方式和网络类型的不同而不同。如果所有MPI_Send调用都替换为MPI_Ssend,那么正确的MPI程序将不会死锁,这意味着您永远不能假设小消息是缓冲的。但是,正确的程序也不会期望MPI_Send对于较大的消息是同步的,并且依赖于这种行为来进行列之间的同步,即,用MPI_Bsend替换MPI_Send并且提供足够大的缓冲区不应该改变程序行为。

有一个非常简单的解决方案总是有效的,它让你不必记住不依赖任何假设——只需使用MPI_Sendrecv。它是一个组合的发送和接收操作,除非发送或接收操作(或两者(不匹配,否则永远不会死锁。通过收发,您的代码将如下所示:

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if (myrank==0) i=1;
if (myrank==1) i=0;
MPI_Sendrecv(sendbuf, 1, MPI_INT, i, 99,
recvbuf, 1, MPI_INT, i, 99, MPI_COMM_WORLD, &status);

最新更新