【问题标题】:MPI - Asynchronous ring communicationMPI - 异步环通信
【发布时间】:2020-03-25 17:57:38
【问题描述】:

我正在尝试实现一个简单的MPI 程序,在该程序中我调用一个函数foo()-n 进程在该函数上传递n 数组,直到所有数组都传递给所有进程(n steps)。该实现采用环形通信的形式,process#0 发送到process#2 并从process#n-1 等接收。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

void foo(double* X, int n,int d,int k)
{
    int id, world_size;
    double *array = X;
    double *array_buff = malloc(n*d*sizeof(double));

    MPI_Comm_rank(MPI_COMM_WORLD,  &id);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    MPI_Status status;

    array[0] = id;

    for(int step = 0 ; step < world_size ; step++)
    {
        int temp = id-step;
        if(temp<0)
        {
            temp = world_size+temp;
        }

        if(array[0]!= temp)
        {
            printf("[%d][%d] %f (start)\n", id, step, array[0]);
        }

        //even processes send first while odd process receive
        //first in order to avoid deadlock - achieve synchronization
        MPI_Request reqsend, reqrecv;
        int dst = (id+1)%world_size;
        if(id%2 == 0)
        {
            int src = id-1;
            if(id == 0)
            {
                src = world_size-1;
            }
            MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);
            MPI_Irecv(array_buff, n*d, MPI_DOUBLE, src, 0, MPI_COMM_WORLD, &reqrecv);

        }
        else
        {

            MPI_Irecv(array_buff, n*d, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &reqrecv);
            MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);

        }   

        //..some array[] related work is been done here...           

        if(array[0]!=temp)
        {
            printf("[%d][%d] %f (end)\n", id, step, array[0]);
        }

        //update array asynchronously
        MPI_Wait(&reqrecv, &status);
        array = array_buff;
    }


    free(array);

}

为了避免死锁偶数进程先发送后接收,而奇数进程先接收后发送。

初始化:array[0] = id;旨在控制通信是否正确完成。这就是为什么我使用两个打印,一个在开始,一个在函数结束,以观察 array[] 是否在 array = array_buff; 分配(其中array[] 获取缓冲值)发生之前更改内容。

我得到的输出之一是:

[0][2] 1.000000 (start)
[0][2] 1.000000 (end)
[0][3] 0.000000 (start)
[0][3] 0.000000 (end)
[1][3] 1.000000 (start)
[1][3] 1.000000 (end)
[3][1] 1.000000 (end)
[3][2] 0.000000 (end)
[3][3] 3.000000 (end)

为什么array[] 的内容在array_buff[] 赋值之前被改变了?

注意:我已经读到,在某些 MPI 版本中,在发送完成之前不能使用 array[]Isend() 缓冲区)。但我认为情况并非如此,因为即使我在 Isend() Irecv() 段之后根本不使用 array[],程序行为仍然是一样的。

我尝试设置 标签 以匹配每个特定的发送,使用标识符值是 step value,但我遇到了死锁,我不明白为什么.我将不胜感激。 tag = step;

【问题讨论】:

    标签: c asynchronous buffer mpi send


    【解决方案1】:

    问题是array = array_buff。虽然array[] 在第一步获得了正确的值,但之后当array_buff 在第二、第三等步骤更新时,它也会更改array[] 的内容,因为它们指向相同的内存。

    问题解决了:

    for(int i=0; i<n*d ; i++)
        {
            array[i] = array_buff[i];
        }
    

    【讨论】:

    • sendreq完成之前修改array也是不正确的。
    • 正如我在问题中提到的,我已经读到它对于某些较低版本的 MPI 是不正确的。不是吗?
    • 不,这总是不正确的。如果您的消息“足够短”,您可能会很幸运并且没有遇到问题(消息以急切模式发送),但您不能假设这是 MPI 标准要求的行为。
    • 谢谢我明白了
    猜你喜欢
    • 1970-01-01
    • 2014-08-23
    • 2011-04-17
    • 1970-01-01
    • 2019-05-29
    • 2019-09-22
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多