繁体   English   中英

MPI - 异步环通信

[英]MPI - Asynchronous ring communication

我正在尝试实现一个简单的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 = 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_buff[]赋值之前改变了array[]的内容?

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

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

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

问题通过以下方式解决:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM