首页
学习
活动
专区
圈层
工具
发布

MPI死锁
EN

Stack Overflow用户
提问于 2013-12-08 08:04:14
回答 3查看 12.1K关注 0票数 13

我正在试验MPI,我想知道这段代码是否会导致死锁。

代码语言:javascript
复制
MPI_Comm_rank (comm, &my_rank);
if (my_rank == 0) {
   MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm);
   MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status);
} else if (my_rank == 1) {
   MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm);
   MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status);
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-12-08 08:33:32

MPI_Send可能阻止,也可能不阻止。它将一直阻塞,直到发送方可以重用发送方缓冲区。当缓冲区已经被发送到较低的通信层时,一些实现将返回到调用者。当另一端有匹配的MPI_Recv()时,另一些将返回给调用者。所以这取决于你的MPI实现,这个程序是否会死锁。

因为这个程序在不同的MPI实现中表现不同,你可以考虑重写它,这样就不会有可能的死锁:

代码语言:javascript
复制
MPI_Comm_rank (comm, &my_rank);
if (my_rank == 0) {
   MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm);
   MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status);
} else if (my_rank == 1) {
   MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status);
   MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm);
}

请始终注意,对于每个MPI_Send(),必须有一个配对的MPI_Recv(),两者在时间上是“并行的”。例如,这可能以死锁结束,因为配对的send/recv调用没有及时对齐。它们相互交叉:

代码语言:javascript
复制
RANK 0                          RANK 1
----------                      -------
MPI_Send() ---            ----  MPI_Send()    |
              ---      ---                    |
                 ------                       |
                   --                         | TIME
                 ------                       |
              ---      ---                    |
MPI_Recv() <--            --->  MPI_Recv()    v

另一方面,这些进程不会以死锁结束,当然,前提是在同一通信器域中确实存在等级为0和1的两个进程。

代码语言:javascript
复制
RANK 0                          RANK 1
----------                      -------
MPI_Send() ------------------>  MPI_Recv()   |
                                             | TIME
                                             |
MPI_Recv() <------------------  MPI_Send()   v

如果通信器com的大小不允许秩1(仅0),则上述固定程序可能失败。这样,if-else就不会采用else路由,因此,没有进程会监听MPI_Send(),0级就会死锁。

如果您需要使用当前的通信布局,那么您可能更喜欢使用MPI_Isend()MPI_Issend()来代替非阻塞发送,从而避免死锁。

票数 18
EN

Stack Overflow用户

发布于 2013-12-10 03:35:39

@mcleod_ideafix的帖子非常好。我想添加一些关于非阻塞MPI调用的东西。

大多数MPI实现的方式是将数据从用户缓冲区复制到其他地方。它可能是实现内部的缓冲区,在正确的网络类型上可能会更好。当该数据从用户缓冲区复制出来并且应用程序可以重用该缓冲区时,MPI_SEND调用将返回。这可能是在调用匹配的MPI_RECV之前,也可能不是。发送的数据越大,消息在MPI_RECV调用之前被阻塞的可能性就越大。

避免这种情况的最好方法是使用非阻塞调用MPI_IRECVMPI_ISEND。这样你就可以先发布你的MPI_IRECV,然后再给MPI_ISEND打电话。这避免了消息到达时的额外副本(因为保存它们的缓冲区已经通过MPI_IRECV可用),这使得事情变得更快,并避免了死锁情况。因此,现在您的代码将如下所示:

代码语言:javascript
复制
MPI_Comm_rank (comm, &my_rank);
if (my_rank == 0) {
   MPI_Irecv (recvbuf, count, MPI_INT, 1, tag, comm, &status, &requests[0]);
   MPI_Isend (sendbuf, count, MPI_INT, 1, tag, comm, &requests[1]);
} else if (my_rank == 1) {
   MPI_Irecv (recvbuf, count, MPI_INT, 0, tag, comm, &status, &requests[0]);
   MPI_Isend (sendbuf, count, MPI_INT, 0, tag, comm, &requests[1]);
}
MPI_Waitall(2, request, &statuses);
票数 7
EN

Stack Overflow用户

发布于 2016-07-10 20:16:28

正如mcleod_ideafix解释的那样,您的代码可能会导致死锁。给你:Explanation and two possible issue Solutions, one by rearranging execution order, one by async send recv calls

以下是异步调用的解决方案:

代码语言:javascript
复制
if (rank == 0) {
        MPI_Isend(..., 1, tag, MPI_COMM_WORLD, &req);
        MPI_Recv(..., 1, tag, MPI_COMM_WORLD, &status);
        MPI_Wait(&req, &status);
} else if (rank == 1) {
        MPI_Recv(..., 0, tag, MPI_COMM_WORLD, &status);
        MPI_Send(..., 0, tag, MPI_COMM_WORLD);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20448283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档