关于MPI_Scatter执行器的问题&它的发送缓冲区分配

时间:2011-05-04 06:37:41

标签: mpi

我的第一个想法是MPI_Scatter,并且应该在if(proc_id == 0)子句中使用send-buffer allocation,因为数据应该只被分散一次,每个进程只需要发送缓冲区中的一部分数据,但它无法正常工作。

在应用程序正常运行之前,似乎所有进程都必须执行发送缓冲区分配和MPI_Scatter

所以我徘徊,MPI_Scatter存在的哲学是什么,因为所有进程都可以访问发送缓冲区。

任何帮助都将不胜感激。

<小时/> 修改 我写的代码是这样的:

if (proc_id == 0) {
    int * data = (int *)malloc(size*sizeof(int) * proc_size * recv_size);
    for (int i = 0; i < proc_size * recv_size; i++) data[i] = i;

    ierr = MPI_Scatter(&(data[0]), recv_size, MPI_INT, &recievedata, recv_size, MPI_INT, 0, MPI_COMM_WORLD);
}

我认为,这足以让根进程分散数据,其他进程需要做的就是接收数据。所以我把MPI_Scatter和发送缓冲区定义&amp;分配,在if(proc_id == 0)语句中。没有编译/运行时错误/警告,但其他进程的接收缓冲区没有收到相应的数据部分。

1 个答案:

答案 0 :(得分:4)

您的问题不是很明确,如果您展示了一些您遇到问题的代码,那么问题会更容易理解。这就是我所想的你想要的 - 而我只是猜测这是因为这是一个错误,我看到有人在C制作中对MPI不熟悉。

如果你有这样的代码:

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

int main(int argc, char **argv) {
    int proc_id, size, ierr;
    int *data;
    int recievedata;

    ierr = MPI_Init(&argc, &argv);
    ierr|= MPI_Comm_size(MPI_COMM_WORLD,&size);
    ierr|= MPI_Comm_rank(MPI_COMM_WORLD,&proc_id);

    if (proc_id == 0) {
        data = (int *)malloc(size*sizeof(int));
        for (int i=0; i<size; i++) data[i] = i;
    }

    ierr = MPI_Scatter(&(data[0]), 1, MPI_INT,
             &recievedata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    printf("Rank %d recieved <%d>\n", proc_id, recievedata);

    if (proc_id == 0) free(data);

    ierr = MPI_Finalize();
    return 0;
}

为什么它不起作用,为什么会出现分段错误? 当然其他进程无法访问data;这就是重点。

答案是在非根进程中,不使用sendbuf参数(MPI_Scatter()的第一个参数)。因此,非根进程需要访问data。但你仍然无法解除引用你没有定义的指针。因此,您需要确保所有C代码都有效。但是在所有其他进程中,数据可以是NULL或完全未定义;你必须确保你不会意外地解除引用它。所以这很好用,例如:

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

int main(int argc, char **argv) {
    int proc_id, size, ierr;
    int *data;
    int recievedata;

    ierr = MPI_Init(&argc, &argv);
    ierr|= MPI_Comm_size(MPI_COMM_WORLD,&size);
    ierr|= MPI_Comm_rank(MPI_COMM_WORLD,&proc_id);

    if (proc_id == 0) {
        data = (int *)malloc(size*sizeof(int));
        for (int i=0; i<size; i++) data[i] = i;
    } else {
        data = NULL;
    }

    ierr = MPI_Scatter(data, 1, MPI_INT,      
             &recievedata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    printf("Rank %d recieved <%d>\n", proc_id, recievedata);

    if (proc_id == 0) free(data);

    ierr = MPI_Finalize();
    return 0;
}

如果你在C中使用“多维数组”,并且说散布一行矩阵,那么你必须跳过一两个额外的箍来使这个工作,但它仍然很容易。

<强>更新

请注意,在上面的代码中,所有例程都称为Scatter - 发件人和收件人。 (实际上,发件人也是接收者)。

在消息传递范例中,发送方和接收方都必须合作发送数据。原则上,这些任务可能位于不同的计算机上,可能位于不同的建筑物中 - 它们之间没有任何共享。因此,任务1无法将数据“放入”任务2内存的某些部分。 (请注意,MPI2具有“单面消息”,但即使这样也需要发送方和接收方之间有很大程度的协调,因为必须有一个窗口可以将数据推入或拉出数据。)

这个典型的例子是发送/接收对; (比方说)进程0向进程3发送数据是不够的,进程3也必须接收数据。

MPI_Scatter函数包含发送和接收逻辑。根进程(此处指定为0)发送数据,并且所有接收者都接收到;参与的每个人都必须打电话给例程。 Scatter是MPI Collective Operation的一个示例,其中通信器中的所有任务都必须调用相同的例程。广播,屏障,减少操作和收集操作是其他例子。

如果您只有进程0调用分散操作,您的程序将挂起,等待其他任务参与。