我使用MPI库在Visual c + + + express上编写简单的hello-world程序,并且无法理解,为什么我的代码无效。
MPI_Init( NULL, NULL );
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
int a, b = 5;
MPI_Status st;
MPI_Send( &b, 1, MPI_INT, 0,0, MPI_COMM_WORLD );
MPI_Recv( &a, 1, MPI_INT, 0,0, MPI_COMM_WORLD, &st );
MPI_Send告诉我“DEADLOCK:尝试在没有事先匹配接收的情况下向本地进程发送消息”。如果我先写Recv,程序卡在那里(没有数据,阻塞接收)。 我做错了什么?
我的工作室是visual c ++ 2010 express。来自HPC SDK 2008的MPI(32位)。
答案 0 :(得分:2)
你需要这样的东西:
assert(size >= 2);
if (rank == 0)
MPI_Send( &b, 1, MPI_INT, 1,0, MPI_COMM_WORLD );
if (rank == 1)
MPI_Recv( &a, 1, MPI_INT, 0,0, MPI_COMM_WORLD, &st );
MPI的想法是整个系统一直运转。有时您需要了解您在这个世界中的哪个参与者。"在这种情况下,假设你有两个成员(根据我的断言),你需要让其中一个发送,另一个接收。
另请注意,我更改了" dest"发送的参数,因为0需要发送到1因此1需要从0接收。
如果你愿意,你可以稍后反过来做(如果每个人都需要告诉其他事情),但在这种情况下你可以找到更有效的方法来使用"集体操作&#34 ;你可以与所有同伴交换(发送和接收)。
答案 1 :(得分:1)
在您的示例代码中,您正在发送和接收排名0.如果您只使用1个进程运行MPI程序(这没有意义,但我们会为了争论而接受它),可以使用非阻塞调用而不是阻止版本来完成此工作。它会将您的程序更改为:
MPI_Init( NULL, NULL );
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
int a, b = 5;
MPI_Status st[2];
MPI_Request request[2];
MPI_Isend( &b, 1, MPI_INT, 0,0, MPI_COMM_WORLD, &request[0] );
MPI_Irecv( &a, 1, MPI_INT, 0,0, MPI_COMM_WORLD, &request[1] );
MPI_Waitall( request, st );
这样可以让发送和接收同时完成。你的MPI版本不喜欢原始代码的原因(非常好的告诉你这样的事情)是因为对MPI_SEND
的调用可能会阻塞,直到完成匹配的MPI_RECV
,在这种情况下不会发生,因为它只会在MPI_SEND
结束后被调用,这是一个循环依赖。
在MPI中,当您在MPI呼叫之前添加“I”时,它表示“立即”,因为呼叫将立即返回并在您稍后拨打MPI_WAIT
(或某些呼叫)时完成所有工作它的版本,如本例中的MPI_WAITALL
。所以我们在这里做的是立即发送和接收返回,基本上只是告诉MPI我们打算在将来的某个时刻进行发送和接收等级0,然后(稍后一行),我们告诉MPI继续现在完成这些电话。
使用这些调用的直接版本的好处是理论上,MPI可以在后台执行一些操作,让发送和接收调用在您的应用程序执行其他不依赖于那个数据。然后,当您稍后完成对MPI_WAIT*
的调用时,数据可用,您可以做任何您需要做的事情。