отправлять и получать массив в MPI - PullRequest
0 голосов
/ 01 июня 2018

Я новичок в MPI и пишу простую программу MPI для получения точечного произведения матрицы и вектора, а именно, A * b = c.Тем не менее, мой код не работает.Исходный код приведен ниже.

Если я заменю объявление A, b, c и buffer на

double A[16], b[4], c[4], buffer[8];

и прокомментирую те строки, которые относятся к операциям выделения и освобождения, мой код работаети результат верный.В данном случае мне было интересно, что проблема должна быть связана с указателями, но я не знаю, как ее устранить.

Еще одна вещь, в моем коде, буфер имеет только 4 элемента, но размер буферадолжно быть больше 8 или не работает.

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

using namespace std;

int nx = 4, ny = 4, nxny;
int ix, iy;
double *A = nullptr, *b = nullptr, *c = nullptr, *buffer = nullptr;
double ans;

// info MPI
int myGlobalID, root = 0, numProc;
int numSent;
MPI_Status status;

// functions
void get_ixiy(int);

int main(){

  MPI_Init(NULL, NULL);
  MPI_Comm_size(MPI_COMM_WORLD, &numProc);
  MPI_Comm_rank(MPI_COMM_WORLD, &myGlobalID);

  nxny = nx * ny;

  A = new double(nxny);
  b = new double(ny);
  c = new double(nx);
  buffer = new double(ny);

  if(myGlobalID == root){
    // init A, b
    for(int k = 0; k < nxny; ++k){
      get_ixiy(k);
      b[iy] = 1;
      A[k] = k;
    }
    numSent = 0;

    // send b to each worker processor
    MPI_Bcast(&b, ny, MPI_DOUBLE, root, MPI_COMM_WORLD);

    // send a row of A to each worker processor, tag with row number
    for(ix = 0; ix < min(numProc - 1, nx); ++ix){
      for(iy = 0; iy < ny; ++iy){
        buffer[iy] = A[iy + ix * ny];
      }
      MPI_Send(&buffer, ny, MPI_DOUBLE, ix+1, ix+1, MPI_COMM_WORLD);
      numSent += 1;
    }

    for(ix = 0; ix < nx; ++ix){
      MPI_Recv(&ans, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
      int sender = status.MPI_SOURCE;
      int ansType = status.MPI_TAG;
      c[ansType] = ans;

      // send another row to worker process
      if(numSent < nx){
        for(iy = 0; iy < ny; ++iy){
          buffer[iy] = A[iy + numSent * ny];
        }
        MPI_Send(&buffer, ny, MPI_DOUBLE, sender, numSent+1, 
        MPI_COMM_WORLD);
        numSent += 1;
      }
      else
        MPI_Send(MPI_BOTTOM, 0, MPI_DOUBLE, sender, 0, MPI_COMM_WORLD);
    }

    for(ix = 0; ix < nx; ++ix){
      std::cout << c[ix] << " ";
    }
    std::cout << std::endl;

    delete [] A;
    delete [] b;
    delete [] c;
    delete [] buffer;
  }
  else{
    MPI_Bcast(&b, ny, MPI_DOUBLE, root, MPI_COMM_WORLD);
      if(myGlobalID <= nx){
        while(1){
          MPI_Recv(&buffer, ny, MPI_DOUBLE, root, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
          if(status.MPI_TAG == 0) break;
          int row = status.MPI_TAG - 1;
          ans = 0.0;

          for(iy = 0; iy < ny; ++iy) ans += buffer[iy] * b[iy];

          MPI_Send(&ans, 1, MPI_DOUBLE, root, row, MPI_COMM_WORLD);
      }
    }
  }

  MPI_Finalize();
  return 0;
} // main

void get_ixiy(int k){
  ix = k / ny;
  iy = k % ny;
}

Информация об ошибке приведена ниже.

=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   PID 7455 RUNNING AT ***
=   EXIT CODE: 11
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES

YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault: 
11 (signal 11)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions

1 Ответ

0 голосов
/ 01 июня 2018

В вашем коде есть несколько проблем, которые вы должны сначала исправить.

Во-первых, вы хотите получить доступ к элементу b[], который не существует, в этом цикле for:

for(int k = 0; k < nxny; ++k){
  get_ixiy(k);
  b[k] = 1;     // WARNING: this is an error
  A[k] = k;
}

Во-вторых, вы удаляете выделенную память только для корневого процесса.Это вызывает утечку памяти:

if(myGlobalID == root){
  // ...
  delete [] A;
  delete [] b;
  delete [] c;
  delete [] buffer;
}

Вы должны удалить выделенную память для всех процессов.

В-третьих, у вас есть бесполезная функция void get_ixiy(int);, которая изменяет глобальные переменные ix, iy,Это бесполезно, потому что после вызова этой функции вы никогда не используете ix, iy, пока не измените их вручную.Смотрите здесь:

for(ix = 0; ix < min(numProc - 1, nx); ++ix){
    for(iy = 0; iy < ny; ++iy){
        // ...
    }
}

В-четвертых, вы используете MPI_Send() и MPI_Recv() совершенно неправильно.Вам повезло, что вы не получили больше ошибок.

...