c++ - MPI 发送/接收错误

标签 c++ mpi

我用 C++ 编写了一个测试程序,以确保我了解 MPI 发送/接收的工作原理(显然我不了解。)该测试在 4 个处理器上运行。我感兴趣的具体情况是,处理器 0 将数组“send_n”发送到处理器 2,处理器 2 在数组“recv_s”中接收它。在初始发送之后,数组是正确的(它应该都是 5),但是在我做了一些额外的发送/接收之后,数组不知何故发生了变化。我在这里做错了什么?

#include <stdlib.h>
#include <iostream>

using namespace std;
# include "mpi.h"
void passBCs(double recv_n[],double recv_e[],double recv_s[],double recv_w[]);
int getNextProcID(int pID, int direction);
int procID,numProcs;
int gridx=2,gridy=2;
int procGridX=2, procGridY=2; 
int main(){
int i,j,k;
int cryptIDs[2]={0,3};
int villusIDs[2]={1,2};

double recv_n[gridx*5],recv_e[gridy*5],recv_s[gridx*5],recv_w[gridy*5];

MPI::Init();
procID=MPI::COMM_WORLD.Get_rank();
numProcs=MPI::COMM_WORLD.Get_size();
if(procID==0){cout<<"MPI Initialized\n";}


passBCs(recv_n,recv_e,recv_s,recv_w);   
MPI::COMM_WORLD.Barrier();



if(procID==2){
for(i=0;i<10;i++){cout<<"Test Buffer="<<recv_s[i]<<"\n";}}

MPI::Finalize();    

if(procID==0){cout<<"Test Run Exiting Normally\n";}

}   


 void passBCs(double recv_n[],double recv_e[],double recv_s[],double recv_w[]){
int i,j,k,nId,eId,sId,wId,n_rId,e_rId,s_rId,w_rId;
int ntag,etag,stag,wtag;
double send_n[gridx*5],send_e[gridy*5],send_s[gridx*5],send_w[gridy*5];


ntag=0;
etag=1;
stag=2;
wtag=3;

if(procID==0){
for(i=0;i<10;i++){
    send_n[i]=5;
    send_s[i]=1;
    send_e[i]=2;
    send_w[i]=3;
}}
else{   for(i=0;i<10;i++){
    send_n[i]=0;
    send_s[i]=0;
    send_e[i]=0;
    send_w[i]=0;
}}


nId=getNextProcID(procID,0);
eId=getNextProcID(procID,1);
sId=getNextProcID(procID,2);
wId=getNextProcID(procID,3);

n_rId=getNextProcID(procID,2);
e_rId=getNextProcID(procID,3);
s_rId=getNextProcID(procID,0);
w_rId=getNextProcID(procID,1);

if(procID==2){cout<<"South Recv ID="<<n_rId<<"\n";}
if(procID==0){cout<<"Proc 0 sending North to "<<nId<<"\n";}

MPI::COMM_WORLD.Send(&send_n[0],20,MPI::DOUBLE,nId,ntag);
MPI::COMM_WORLD.Recv(&recv_s[0],20,MPI::DOUBLE,n_rId,ntag);
if(procID==2){
for(i=0;i<10;i++){cout<<"Test Buffer0="<<recv_s[i]<<"\n";}}

MPI::COMM_WORLD.Send(&send_e[0],20,MPI::DOUBLE,eId,etag);
MPI::COMM_WORLD.Recv(&recv_w[0],20,MPI::DOUBLE,e_rId,etag);
if(procID==2){
for(i=0;i<10;i++){cout<<"Test Buffer1="<<recv_s[i]<<"\n";}}

MPI::COMM_WORLD.Send(&send_s[0],20,MPI::DOUBLE,sId,stag);
MPI::COMM_WORLD.Recv(&recv_n[0],20,MPI::DOUBLE,s_rId,stag);

MPI::COMM_WORLD.Send(&send_w[0],20,MPI::DOUBLE,wId,wtag);
MPI::COMM_WORLD.Recv(&recv_e[0],20,MPI::DOUBLE,w_rId,wtag);

}

int getNextProcID(int pID, int direction){
//Returns the ID number for the processor that is "direction" to the give proc id.
//0=north,1=east,2=south,3=west;
int x_pos,y_pos,nextID; 
x_pos=pID%procGridX;
y_pos=pID/procGridY;
if(direction==0){y_pos++;}
if(direction==1){x_pos++;}
if(direction==2){y_pos--;}
if(direction==3){x_pos--;}
if(x_pos<0){x_pos=procGridX-1;}
if(x_pos>=procGridX){x_pos=0;}
if(y_pos<0){y_pos=procGridY-1;}
if(y_pos>=procGridY){y_pos=0;}
nextID=y_pos*procGridY+x_pos;
return nextID;  
}

输出是:

MPI Initialized
South Recv ID=0
Proc 0 sending North to 2
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=0
Test Buffer1=5
Test Buffer1=5
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=0
Test Buffer=5
Test Buffer=5
Test Run Exiting Normally

最佳答案

我认为您观察到的错误是由您对文件所做的不一致编辑的不幸组合或对 count 的错误解释造成的MPI::COMM_WORLD.Send 的参数. 来自 OpenMPI 的文档:

void Comm::Send(const void* buf, int count, const Datatype& datatype, int dest, int tag) const

buf: Initial address of send buffer (choice).

count: Number of elements send (nonnegative integer).

datatype: Datatype of each send buffer element (handle).

dest: Rank of destination (integer).

tag: Message tag (integer).

comm: Communicator (handle).

请注意,count 参数是由第三个参数定义的 elements 数量(不是某种与类型无关的大小度量)。显然,您最初在数组中有 20 个元素,或者您认为 count参数表示发送缓冲区的大小,以 4 字节 block 为单位。无论如何,您的 MPI 命令引用 20 个元素,例如 MPI::COMM_WORLD.Send(&send_n[0],20,MPI::DOUBLE,nId,ntag); .因此,Recv命令将从数组末尾之外发送的数据写入目标数组末尾之外的位置!您很幸运没有看到段错误(再次幸运,因为编译器将您的数组彼此相邻,因此您实际上看到了在数组外写入的效果)。我刚刚编译了你的程序,替换了所有那些 2010 s 并且它运行良好(我没有重新发布代码,因为它只是一个如此简单的更改)。

修改后的输出:

MPI Initialized
Proc 0 sending North to 2
South Recv ID=0
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer0=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer1=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Buffer=5
Test Run Exiting Normally

为避免将来出现这些错误,请将数组的大小与 count 结合起来你传递给 Send命令,例如,通过一些编译时间常量或预处理器宏。既然你一直在使用 C++,为什么不使用 std::vector<double>而不是双数组,无论它们是如何构建的,您都可以在发送它们之前在运行时确定其大小?

关于c++ - MPI 发送/接收错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24271337/

相关文章:

c++ - 动态分配内存和取消引用

c++ - OpenCV:将图像转换为 C++ 数组

python - 替代 python 脚本中的 mpirun

algorithm - MPI:负载均衡算法(Master-Slave模型)

我可以从不同的 MPI_Irecv 写入不同索引位置的相同缓冲区/数组吗?

c++ - 如何在 Eigen/C++ 中向量化 : set columns under condition

c++ - 空的大小是多少?

c++ - 如何将 AERT_Allocate 与 std :vector 一起使用

c++ - 如果可执行文件在两个或多个节点上运行,为什么无法看到环境变量?

c++ - 将 MPI 等级分配给 gpu