【问题标题】:Infinite loop using MPI_Irecv and MPI_Test使用 MPI_Irecv 和 MPI_Test 的无限循环
【发布时间】:2013-02-26 17:32:38
【问题描述】:

我在 C 语言中的 MPI 程序几乎没有问题。我想用 MPI_Send 从从机向主机发送两条消息(使用 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:对不起我的英语

【问题讨论】:

    标签: c mpi


    【解决方案1】:

    有一件事是你必须在每次等待消息时调用 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;
    
    }
    

    【讨论】:

    • 你能告诉我为什么“每次等待消息时都必须调用 MPI_Irecv”吗?为什么 MPI 不执行类似循环的操作。目的是什么???
    【解决方案2】:

    问题是主人只发布一个接收。您需要将调用移动到循环内的MPI_Irecv,在MPI_Test 成功返回的位置(在if (status.MPI_SOURCE != -1) 块内),以便可以接收后续消息。

    【讨论】:

    • 你能告诉我为什么“主人只发一个收到”吗???为什么 MPI 不执行类似循环的操作。目的是什么???
    猜你喜欢
    • 2018-09-13
    • 2015-07-17
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 2021-12-19
    相关资源
    最近更新 更多