2011-05-04 115 views
2

我的第一个想法是MPI_Scatter,应该在if(proc_id == 0)子句中使用发送缓冲区分配,因为数据只应该分散一次,每个进程只需要发送缓冲区中的一部分数据但是它没有正常工作。关于MPI_Scatter执行器及其发送缓冲区分配的问题

看来发送缓冲区分配和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,以及发送缓冲区定义&分配,在if(proc_id == 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 - 发送方和recievers。 (实际上,发件人也是一个接收者)。

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

这是一个典型的例子是send/recieve pairs; (例如)进程0向进程3发送数据是不够的,进程3也必须接收数据。

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

如果你只有进程0调用scatter操作,你的程序将挂起,永远等待其他任务参与。

+0

我发布了我的代码片段,就像你看到我在PThread逻辑中想的那样,共享内存充当通信方式。我对mpi没有太多的了解。 – user435657 2011-05-04 14:28:45

+0

我已更新答案以更好地反映您的问题。 – 2011-05-04 19:08:17

+0

非常感谢,您的确了解了MPI的原理。 – user435657 2011-05-05 00:56:09