与多对多处理器通信时出现MPI错误

时间:2017-03-13 09:19:16

标签: c++ mpi openmpi

我正在编写代码,其中每个处理器必须与多个处理器进行交互。

Ex:我有12个处理器,所以处理器0必须通信说1,2,10和9.让我们称它们为处理器0的邻居。同样我有 处理器1必须与5,3进行通信。 处理器2必须与5,1,0,10,11通信 等等。 数据流是2种方式,即处理器0必须将数据发送到1,2,10和9,并且还从它们接收数据。 此外,标签计算没有问题。 我创建了一个代码如下:

for(all neighbours) 
{
store data in vector<double> x;

     MPI_Send(x)
}
MPI_BARRIER();
for(all neighbours)
{
MPI_Recv(x);
do work with x
}

现在我针对不同大小的x和不同的邻居排列测试这个算法。代码适用于某些人,但不适用于其他人,它只是解决死锁问题。 我也尝试过:

for(all neighbours) 
{
store data in vector<double> x;

     MPI_ISend(x)
}
MPI_Test();
for(all neighbours)
{
MPI_Recv(x);
do work with x
}

结果是一样的,虽然死因在结果中由NaN重新复制,因为MPI_Test()告诉我某些MPI_Isend()操作没有完成,它会立即跳转到MPI_Recv()。

任何人都可以指导我这件事,我错了什么?或者我的基本方法本身是不正确的?

编辑:我附上了代码段,以便更好地理解问题。我基本上致力于并行化非结构化3D-CFD求解器

我附上了其中一个文件,但有一些解释。我不是广播,我正在循环访问父处理器的邻居以通过接口发送数据(这可以定义为两个接口之间的边界)。

所以,如果说我有12个处理器,并说处理器0必须通信说1,2,10和9.所以0是父处理器,1,2,10和9是它的邻居。

由于文件太长而且是解算器的一部分,为了简单起见,我只保留了MPI函数。

void Reader::MPI_InitializeInterface_Values() {
double nbr_interface_id;
Interface *interface;
MPI_Status status;
MPI_Request send_request, recv_request;
int err, flag;
int err2;
char buffer[MPI_MAX_ERROR_STRING];
int len;
int count;


for (int zone_no = 0; zone_no<this->GetNumberOfZones(); zone_no++) { // Number of zone per processor is 1, so basically each zone is an independent processor
    UnstructuredGrid *zone = this->ZoneList[zone_no];
    int no_of_interface = zone->GetNumberOfInterfaces();
    // int count;
    long int count_send = 0;
    long int count_recv = 0;
    long int max_size = 10000; // can be set from test case later
    int max_size2 = 199;

    int proc_no = FlowSolution::processor_number;
    for (int interface_no = 0; interface_no < no_of_interface; interface_no++) { // interface is defined as a boundary between two zones


        interface = zone->GetInterface(interface_no);
        int no_faces = interface->GetNumberOfFaces();
        if (no_faces != 0) {

            std::vector< double > Variable_send; // The vector which stores the data to be sent across the interface
            std::vector< double > Variable_recieve;
            int total_size = FlowSolution::VariableOrder.size() * no_faces;
            Variable_send.resize(total_size);
            Variable_recieve.resize(total_size);
            int nbr_proc_no = zone->GetInterface(interface_no)->GetNeighborZoneId(); // neighbour of parent processor

                int j = 0;
                nbr_interface_id = interface->GetShared_Interface_ID();

                for (std::map<VARIABLE, int>::iterator iterator = FlowSolution::VariableOrder.begin(); iterator != FlowSolution::VariableOrder.end(); iterator++) {

                    for (int face_no = 0; face_no < no_faces; face_no++) {
                        Face *face = interface->GetFace(face_no);
                        int owner_id = face->Getinterface_Original_face_owner_id();
                        double value_send = zone->GetInterface(interface_no)->GetFace(face_no)->GetCell(owner_id)->GetPresentFlowSolution()->GetVariableValue((*iterator).first);
                        Variable_send[j] = value_send;
                        j++;
                    }
                }
                count_send = nbr_proc_no * max_size + nbr_interface_id; // tag for data to be sent
                err2 = MPI_Isend(&Variable_send.front(), total_size, MPI_DOUBLE, nbr_proc_no, count_send, MPI_COMM_WORLD, &send_request);
        }// end of sending

    } // all the processors have sent data to their corresponding neighbours

    MPI_Barrier(MPI_COMM_WORLD);

    for (int interface_no = 0; interface_no < no_of_interface; interface_no++) { // loop over of neighbours of the current processor to receive data

        interface = zone->GetInterface(interface_no);
        int no_faces = interface->GetNumberOfFaces();
        if (no_faces != 0) {
            std::vector< double > Variable_recieve; // The vector which collects the data sent across the interface from 
            int total_size = FlowSolution::VariableOrder.size() * no_faces;
            Variable_recieve.resize(total_size);
            count_recv = proc_no * max_size + interface_no; // tag to receive data
            int nbr_proc_no = zone->GetInterface(interface_no)->GetNeighborZoneId();
            nbr_interface_id = interface->GetShared_Interface_ID();
                MPI_Irecv(&Variable_recieve.front(), total_size, MPI_DOUBLE, nbr_proc_no, count_recv, MPI_COMM_WORLD, &recv_request);

                /* Now some work is done using received data */
                int j = 0;
                for (std::map<VARIABLE, int>::iterator iterator = FlowSolution::VariableOrder.begin(); iterator != FlowSolution::VariableOrder.end(); iterator++) {
                    for (int face_no = 0; face_no < no_faces; face_no++) {
                        double value_recieve = Variable_recieve[j];
                        j++;
                        Face *face = interface->GetFace(face_no);
                        int owner_id = face->Getinterface_Original_face_owner_id();
                        interface->GetFictitiousCell(face_no)->GetPresentFlowSolution()->SetVariableValue((*iterator).first, value_recieve);
                        double value1 = face->GetCell(owner_id)->GetPresentFlowSolution()->GetVariableValue((*iterator).first);
                        double face_value = 0.5 * (value1 + value_recieve);
                        interface->GetFace(face_no)->GetPresentFlowSolution()->SetVariableValue((*iterator).first, face_value);
                    }
                }
                // Variable_recieve.clear();

        }

    }// end of receiving

}

3 个答案:

答案 0 :(得分:0)

使用问题陈述:

  • 处理器0必须发送到1,2,9和10,并从中接收。
  • 处理器1必须发送到5和3,并从中接收。
  • 处理器2必须发送到0,1,5,10和11,并从中接收。
  • 共有12个处理器。

如果你只是运行一个12步程序,你可以让生活更轻松:

  • 步骤1:处理器0发送,其他人根据需要接收,然后发生相反的情况。
  • 步骤2:处理器1发送,其他人根据需要接收,然后发生相反的情况。
  • ...
  • 第12步:获利 - 没有什么可做的(因为每个其他处理器已经与处理器11进行了互动)。

每个步骤都可以实现为MPI_Scatterv(一些sendcounts将为零),然后是MPI_Gatherv。总共有22个电话,你已经完成了。

答案 1 :(得分:0)

可能有几种可能的死锁原因,所以你必须更加具体,e。 G。标准说:&#34;当使用标准发送操作时,可能会发生死锁情况,因为缓冲区空间不可用,两个进程都被阻塞。&#34;

你应该同时使用Isend和Irecv。一般结构应该是:

MPI_Request req[n];

MPI_Irecv(..., req[0]);
// ...
MPI_Irecv(..., req[n-1]);
MPI_Isend(..., req[0]);
// ...
MPI_Isend(..., req[n-1]);

MPI_Waitall(n, req, MPI_STATUSES_IGNORE);

答案 2 :(得分:0)

通过使用AllGatherV,问题可以解决。我所做的就是发送计数,使发送计数只有我想要与之通信的处理器。其他处理器有0个发送计数。 这解决了我的问题

谢谢大家的答案!