我正在试验MPI,我想知道这段代码是否会导致死锁。
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);
}发布于 2013-12-08 08:33:32
MPI_Send可能阻止,也可能不阻止。它将一直阻塞,直到发送方可以重用发送方缓冲区。当缓冲区已经被发送到较低的通信层时,一些实现将返回到调用者。当另一端有匹配的MPI_Recv()时,另一些将返回给调用者。所以这取决于你的MPI实现,这个程序是否会死锁。
因为这个程序在不同的MPI实现中表现不同,你可以考虑重写它,这样就不会有可能的死锁:
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调用没有及时对齐。它们相互交叉:
RANK 0 RANK 1
---------- -------
MPI_Send() --- ---- MPI_Send() |
--- --- |
------ |
-- | TIME
------ |
--- --- |
MPI_Recv() <-- ---> MPI_Recv() v另一方面,这些进程不会以死锁结束,当然,前提是在同一通信器域中确实存在等级为0和1的两个进程。
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()来代替非阻塞发送,从而避免死锁。
发布于 2013-12-10 03:35:39
@mcleod_ideafix的帖子非常好。我想添加一些关于非阻塞MPI调用的东西。
大多数MPI实现的方式是将数据从用户缓冲区复制到其他地方。它可能是实现内部的缓冲区,在正确的网络类型上可能会更好。当该数据从用户缓冲区复制出来并且应用程序可以重用该缓冲区时,MPI_SEND调用将返回。这可能是在调用匹配的MPI_RECV之前,也可能不是。发送的数据越大,消息在MPI_RECV调用之前被阻塞的可能性就越大。
避免这种情况的最好方法是使用非阻塞调用MPI_IRECV和MPI_ISEND。这样你就可以先发布你的MPI_IRECV,然后再给MPI_ISEND打电话。这避免了消息到达时的额外副本(因为保存它们的缓冲区已经通过MPI_IRECV可用),这使得事情变得更快,并避免了死锁情况。因此,现在您的代码将如下所示:
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);发布于 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
以下是异步调用的解决方案:
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);
}https://stackoverflow.com/questions/20448283
复制相似问题