我在C中使用MPI程序时遇到的问题很少。我想用MPI_Send从slave发送两条消息到master(使用MPI_Send,MPI_Irecv和MPI_Test),但只有第一条消息有效。在那之后,我有一个无限循环,我总是收到来自奴隶-1的消息(根据status.MPI_Source)。
所以我不明白为什么我收到来自未知进程的所有这些消息(-1)......
我的代码:
#include <stdio.h>
#include <mpi.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
int rank, size;
MPI_Status status;
/* Init */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank != 0) { // Slaves
int buf;
if (rank == 1) {
buf = 1;
MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
if (rank == 2) {
buf = 2;
MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
}
else { // Master
int sum = 0;
int flag, res;
MPI_Request request;
MPI_Status status;
MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request);
while (1) {
flag = 0;
MPI_Test(&request, &flag, &status);
if (flag != 0) {
printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE);
if (status.MPI_SOURCE != -1)
sum += res;
}
else
printf("fail!\n");
if (sum == 3)
break;
}
printf("sum : %d\n", sum);
}
MPI_Finalize();
return 0;
}
感谢。
ps:抱歉我的英文
答案 0 :(得分:10)
有一点是每次收到消息时都必须调用MPI_Irecv。所以在你的情况下,你必须打电话2次。不多也不少。
让我们看一下仅通过在循环内移动MPI_Irecv调用而改变的代码。 这不正确。不行。
else { // Master
int sum = 0;
int flag, res;
MPI_Request request;
MPI_Status status;
while (1) {
flag = 0;
MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request);
MPI_Test(&request, &flag, &status);
if (flag != 0) {
printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE);
if (status.MPI_SOURCE != -1)
sum += res;
}
else
printf("fail!\n");
if (sum == 3)
break;
}
假设传递由奴隶发送的消息的随机时间(当我们谈论分布式系统或线程时总是如此),很容易想象出这种情况: 时间的推移|事件
0 | called first MPI_Irecv, allocated memory for MPI_Request object
1 | called second MPI_Irecv, allocated memory for MPI_Request (lets say) object2
2 | called third MPI_Irecv, allocated memory for MPI_Request object3
3 | called MPI_Send in slave no. 1
4 | called MPI_Send in slave no. 2
5 | received message by master from slave no. 1, filled object, flag variable still 0 because its related to object3
6 | received message by master from slave no. 2, filled object2, flag variable still 0 because its related to object3
7,8,9... | infinite loop, flag still has value 0
n | error: MPI_Irecv(147): MPI_Irecv(buf=0x7fffecfa60c4, count=1, MPI_INT, src=MPI_ANY_SOURCE, tag=MPI_ANY_TAG, MPI_COMM_WORLD, request=0x7fffecfa60c8)
MPID_Irecv(53): failure occurred while allocating memory for a request object
有两种解决方案。你可以通过在while循环之前调用sleep(3)来减慢Master进程,所以它肯定会在稍后启动,然后调用MPI_Send。
其次,更好的工程方法是仅在我们期待消息时调用MPI_Irecv。最初调用MPI_Irecv并将值0赋给该标志。在我们再次收到消息更改标志为-1并且仅在标志具有-1值时调用MPI_Irecv。
以下是代码可行:
#include <stdio.h>
#include <mpi.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
int rank, size;
MPI_Status status;
/* Init */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank != 0) { // Slaves
int buf;
if (rank == 1) {
buf = 1;
MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
if (rank == 2) {
buf = 2;
MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
}
else { // Master
int sum = 0;
int flag = -1, res;
MPI_Request request;
MPI_Status status;
while (1) {
if(flag != 0)
{
MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request);
flag = 0;
}
MPI_Test(&request, &flag, &status);
if (flag != 0) {
printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE);
if (status.MPI_SOURCE != -1)
sum += res;
flag = -1;
}
if (sum == 3)
break;
}
printf("sum : %d\n", sum);
}
MPI_Finalize();
return 0;
}
答案 1 :(得分:4)
问题是主人只发帖一次。您需要在MPI_Irecv
成功返回的位置(MPI_Test
块内)将调用移动到循环内if (status.MPI_SOURCE != -1)
,以便可以接收后续消息。 / p>