【问题标题】:A simple MPI program一个简单的 MPI 程序
【发布时间】:2011-08-19 04:48:18
【问题描述】:

如果有人告诉我为什么这个简单的 MPI 发送和接收代码不能在 两个处理器上运行,当 n=40(在第 20 行)的值,但适用于 n 时,我将不胜感激

#include "mpi.h"
#include "stdio.h"
#include "stdlib.h"
#include "iostream"
#include "math.h"
using namespace std;

int main(int argc, char *argv[])
{
    int processor_count, processor_rank;
    double *buff_H, *buff_send_H;
    int N_pa_prim1, l, n, N_p0;
    MPI_Status status;

    MPI_Init (&argc, &argv);
    MPI_Comm_size (MPI_COMM_WORLD, &processor_count);
    MPI_Comm_rank (MPI_COMM_WORLD, &processor_rank);

    N_pa_prim1=14; l=7; n=40; N_p0=7;
    buff_H = new double [n*n*N_p0+1];          //Receive buffer allocation

    buff_send_H = new double [n*n*N_p0+1];     //Send buffer allocation

    for (int j = 0; j < n*n*N_p0+1; j++)
        buff_send_H[j] = 1e-8*rand();

    if (processor_rank == 0)
        MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD);  
else if(processor_rank == 1)
    MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD);

    MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
cout << "Received successfully by " << processor_rank << endl;
MPI_Finalize();
return 0;
}

【问题讨论】:

    标签: mpi parallel-processing sendmessage


    【解决方案1】:

    死锁是正确的行为;你的代码出现了死锁。

    MPI 规范允许MPI_Send 的行为与MPI_Ssend 一样——即阻塞。阻塞通信原语在某种意义上的通信“完成”之前不会返回,这(在阻塞发送的情况下)可能意味着接收已经开始。

    您的代码如下所示:

    If Processor 0:
       Send to processor 1
    
    If Processor 1:
       Send to processor 0
    
    Receive
    

    也就是说——在发送完成之前接收不会开始。您正在发送,但他们永远不会返回,因为没有人接收! (这适用于小消息的事实是一个实现工件 - 大多数 mpi 实现使用所谓的“渴望协议”来处理“足够小”的消息;但这通常不能指望。)

    请注意,这里也存在其他逻辑错误 - 此程序还会在超过 2 个处理器时死锁,因为 rank >= 2 的处理器将等待一条永远不会到来的消息。

    您可以通过按等级交替发送和接收来修复您的程序:

    if (processor_rank == 0) {
        MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD);  
        MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
    } else if (processor_rank == 1) {
        MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
        MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD);
    }
    

    或使用 MPI_Sendrecv(这是一个阻塞(发送 + 接收),而不是阻塞发送 + 阻塞接收):

    int sendto;
    if (processor_rank == 0)
        sendto = 1;
    else if (processor_rank == 1)
        sendto = 0;
    
    if (processor_rank == 0 || processor_rank == 1) {
        MPI_Sendrecv(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, sendto, 163,
                     buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163,
                     MPI_COMM_WORLD, &status);
    }
    

    或者通过使用非阻塞发送和接收:

    MPI_Request reqs[2];
    MPI_Status  statuses[2];
    if (processor_rank == 0) {
        MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD, &reqs[0]);
    } else if (processor_rank == 1) {
        MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD, &reqs[0]);
    }
    
    if (processor_rank == 0 || processor_rank == 1)
        MPI_Irecv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &reqs[1]);
    
    MPI_Waitall(2, reqs, statuses);
    

    【讨论】:

      【解决方案2】:

      感谢乔纳森的帮助。在这里,我选择了第三种解决方案并编写了与您的类似的代码,只是添加了“for”循环来发送大量消息。这次它没有死锁;但是处理器继续只接收最后一条消息。 (由于消息很长,我只打印了它们的最后一个元素以检查一致性)

      #include <mpi.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <iostream>
      #include <math.h>
      using namespace std;
      
      int main(int argc, char *argv[])
      {
      int processor_count, processor_rank;
      
      //Initialize MPI
      MPI_Init (&argc, &argv);
      MPI_Comm_size (MPI_COMM_WORLD, &processor_count);
      MPI_Comm_rank (MPI_COMM_WORLD, &processor_rank);
      
      double **buff_H, *buff_send_H;
      int N_pa_prim1, l, n, N_p0, count, temp;
      N_pa_prim1=5; l=7; n=50; N_p0=7;
      
      MPI_Request reqs[N_pa_prim1];
      MPI_Status  statuses[N_pa_prim1];
      buff_H = new double *[N_pa_prim1];                 //Receive buffer allocation
      for (int i = 0; i < N_pa_prim1; i++)
          buff_H[i] = new double [n*n*N_p0+1];  
      buff_send_H = new double [n*n*N_p0+1];             //Send buffer allocation
      
      if (processor_rank == 0) {
          for (int i = 0; i < N_pa_prim1; i++){
              for (int j = 0; j < n*n*N_p0+1; j++)
                  buff_send_H[j] = 2.0325e-8*rand();
      
              cout << processor_rank << "\t" << buff_send_H[n*n*N_p0] << "\t" << "Send" << "\t" << endl;  
              MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD, &reqs[i]);
          }
      }
      else if (processor_rank == 1) {
          for (int i = 0; i < N_pa_prim1; i++){
              for (int j = 0; j < n*n*N_p0+1; j++)
                  buff_send_H[j] = 3.5871e-8*rand();
      
              cout << processor_rank << "\t" << buff_send_H[n*n*N_p0] << "\t" << "Send" << "\t" << endl;  
              MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD, &reqs[i]);
          }
      }
      
      for (int i = 0; i < N_pa_prim1; i++)
          MPI_Irecv(buff_H[i], n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &reqs[N_pa_prim1+i]);
      
      MPI_Waitall(2*N_pa_prim1, reqs, statuses);
      
      for (int i = 0; i < N_pa_prim1; i++)
          cout << processor_rank << "\t" << buff_H[i][n*n*N_p0] << "\t" << "Receive" << endl;
      
      MPI_Finalize();
      return 0;
      

      }

      【讨论】:

        猜你喜欢
        • 2011-08-22
        • 2013-01-13
        • 2014-06-07
        • 2014-08-20
        • 1970-01-01
        • 2014-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多