MPI 的死锁
(2011-04-15 20:22:44)
标签:
杂谈 |
分类: 随笔 |
以下是一段MPI的并行测试程序:
#include <stdio.h>
#include "mpi.h"
int main (int argc, char **argv)
{
int rank,
size, next,
prev, message, tag = 200;
MPI_Init
(&argc,
&argv);
MPI_Comm_rank (MPI_COMM_WORLD,
&rank);
MPI_Comm_size (MPI_COMM_WORLD,
&size);
next = (rank
+ 1) % size;
prev = (rank
+ size - 1) % size;
//
if (rank
== 0)
// {
//
MPI_Send (&msg_buf,
msg_count, msg_type,
i, tag,
MPI_COMM_WORLD);
// }
while
(1)
{
MPI_Recv (&message, 1, MPI_INIT, prev, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if (rank == 0)
{
--message;
}
MPI_Send (&message, 1, MPI_INT, next, tag,
MPI_COMM_WOLRD);
if (message == 0)
{
printf ("Process %d exiting\n", rank);
break;
}
}
if (rank ==
0)
{
MPI_Recv (&msg_buf, msg_count, msg_type, prev, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
// if (rank ==
0)
// {
//
MPI_Recv (&msg_buf, msg_count, msg_type, prev, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
// }
MPI_Finialize ();
return
0;
}
这段代码的 while 语句块中,首先是每个进程都要接收数据,但没有发送方,必须等待后面的发送语句生效。而阻塞通信完成的条件是只有接受方接受到数据,通信才结束。由于这时每个进程都在等待接受数据,从而通信还没有结束,也就不会发送。这时候出现了死锁。现在以两个进程为例说明:
也就是,每个进程都在等待别的进程给自己发送数据,而此时又没有发送方。
假设从其中任意取出两个进程 i 和进程 j
i --> j 表示 i 向 j 发送消息,用MPI表示为:
// if (rand == i)
MPI_Send
(&msg_buf, msg_count,
msg_type, j,
tag, MPI_COMM_WORLD);
本函数结束的条件是进程 j 接受到消息
i <-- j 表示 i 从 j 接收消息
// if (rank == j)
MPI_Recv
(&msg_buf,
msg_count, msg_type,
i,
tag, MPI_COMM_WORLD);
本函数结束的条件是 i 接收到消息
i 等待 j 接受到自己发给它的消息,同时 j 等待自己发出的消息被 i 接受。两个进程都在等待对方接受,显然就死锁了。在阻塞通信的过程中,这种死锁是很常见的。解除死锁的方法是在群发之前,有一个独立的进程发送消息给群发进程中的某一个进程。
例如在上述代码中加入如下代码:
if (rank == 0)
{
MPI_Send
(&msg_buf,
msg_count, msg_type,
i, tag, MPI_COMM_WORLD);
}
也就是把代码中的绿色部分解除注释。现在来分析是否会死锁:
0 进程发送出消息给 i 进程,当进入 while 循环后,所有进程都接受数据,i 进程也不例外。此时 i 首先接受到数据,i
进程的通信过程就绪,而其他的进程仍然在等待接收。当运行到MPI_Send语句时,i 进程可以发送,其他进程无法发送。此时,i
进程的死锁解除,其他进程仍然死锁。
如果 i
只是发给自己,而不发给其他进程,i 进程解除死锁,而其他进程还是没有解除死锁。从而,只有 i
与自己通信而已,其他进程仍然不能通信。
例如
if (rank == 0)
{
MPI_Send
(&msg_buf, msg_count, msg_type, 0, tag,
MPI_COMM_WORLD);
}
这时,整个MPI_COMM_WORLD中,只有 0 进程是活动的,其他都是死锁的。
上面的过程只有形成一个消息传递环,则环中的进程才是活动的,而环外的进程是死锁的。例如:
#include <stdio.h>
#include "mpi.h"
int main (int argc, char **argv)
{
int rank,
size, next,
prev, message, tag = 200;
MPI_Init
(&argc,
&argv);
MPI_Comm_rank (MPI_COMM_WORLD,
&rank);
MPI_Comm_size (MPI_COMM_WORLD,
&size);
next = (rank
+ 1) % size;
prev = (rank
+ size - 1) % size;
if (rank ==
0)
{
MPI_Send (&msg_buf,
msg_count, msg_type,
next, tag,
MPI_COMM_WORLD);
}
while
(1)
{
MPI_Recv (&message, 1, MPI_INIT, prev, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
#include <stdio.h>
#include "mpi.h"
int main (int argc, char **argv)
{
//
//
//
//
//
//
//
//
}
这段代码的 while 语句块中,首先是每个进程都要接收数据,但没有发送方,必须等待后面的发送语句生效。而阻塞通信完成的条件是只有接受方接受到数据,通信才结束。由于这时每个进程都在等待接受数据,从而通信还没有结束,也就不会发送。这时候出现了死锁。现在以两个进程为例说明:
也就是,每个进程都在等待别的进程给自己发送数据,而此时又没有发送方。
假设从其中任意取出两个进程 i 和进程 j
i --> j 表示 i 向 j 发送消息,用MPI表示为:
// if (rand == i)
本函数结束的条件是进程 j 接受到消息
i <-- j 表示 i 从 j 接收消息
// if (rank == j)
本函数结束的条件是 i 接收到消息
i 等待 j 接受到自己发给它的消息,同时 j 等待自己发出的消息被 i 接受。两个进程都在等待对方接受,显然就死锁了。在阻塞通信的过程中,这种死锁是很常见的。解除死锁的方法是在群发之前,有一个独立的进程发送消息给群发进程中的某一个进程。
例如在上述代码中加入如下代码:
if (rank == 0)
{
}
也就是把代码中的绿色部分解除注释。现在来分析是否会死锁:
例如
if (rank == 0)
{
}
这时,整个MPI_COMM_WORLD中,只有 0 进程是活动的,其他都是死锁的。
上面的过程只有形成一个消息传递环,则环中的进程才是活动的,而环外的进程是死锁的。例如:
#include <stdio.h>
#include "mpi.h"
int main (int argc, char **argv)
{