Мне нужен редукционный узел, чтобы получить копию списка элементов (хранящегося в векторе) от других узлов. Я определил свою собственную сокращающую функцию, но она не работает. Программа завершается / вылетает.
Это код:
#include <iostream>
#include "mpi.h"#include <vector>
using namespace std;
void pushTheElem(vector<int>* in, vector<int>* inout, int *len, MPI_Datatype *datatype)
{
vector<int>::iterator it;
for (it = in->begin(); it < in->end(); it++)
{
inout->push_back(*it);
}
}
int main(int argc, char **argv)
{
int numOfProc, procID;
vector<int> vect, finalVect;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numOfProc);
MPI_Comm_rank(MPI_COMM_WORLD, &procID);
MPI_Op myOp;
MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp);
for (int i = 0; i < 5; i++)
{
vect.push_back(procID);
}
MPI_Reduce(&vect, &finalVect, 5, MPI_INT, myOp, 0, MPI_COMM_WORLD);
if (procID == 0)
{
vector<int>::iterator it;
cout << "Final vector elements: " << endl;
for (it = finalVect.begin(); it < finalVect.end(); it++)
cout << *it << endl;
}
MPI_Finalize();
return 0;
}
Кажется, вы хотите собрать все элементы из всех процессов. Это не сокращение, это операция по сбору. Редукция объединяет несколько массивов одинаковой длины в массив этой конкретной длины:
Это не тот случай, когда объединение двух массивов дает массив длины, равный сумме входных массивов. С MPI вы не можете просто работать с указателями, как вы пытаетесь сделать в вашей операции сокращения. Вы не можете отправлять указатели с помощью MPI, поскольку процессы имеют отдельное адресное пространство. Интерфейс MPI использует указатели, но только области данных, содержащие известные типы и известный размер.
Вы можете легко сделать свою задачу с MPI_Gather
,
// vect.size() must be the same on every process, otherwise use MPI_Gatherv
// finalVect is only needed on the root.
if (procID == 0) finalVect.resize(numOfProc * vect.size());
MPI_Gather(vect.data(), 5, MPI_INT, finalVect.data(), 5, MPI_INT, 0, MPI_COMM_WORLD);
Я не думаю, что вы можете передавать векторы, используя MPI таким образом. Что MPI делает, он берет первый указатель и интерпретирует его как двоичный объект данных типа INT и определенной длины. Пожалуйста, подумайте, как реализован вектор. Сам вектор представляет собой небольшую управляющую структуру, которая указывает на некоторый массив в куче. Таким образом, передавая вектор *, вы предоставляете не указатель на данные, а эту управляющую структуру, которая затем приводит к неопределенному поведению, когда ваша программа пытается использовать его в качестве вектора.
Вам нужно работать с необработанными данными с помощью MPI. Попробуйте это (не проверено, так как у меня нет MPI под рукой):
#include <iostream>
#include "mpi.h"#include <vector>
using namespace std;
void pushTheElem(int* in, int* inout, int *len, MPI_Datatype *datatype)
{
for(inti=0;i<*len;++i){
inout[i]=in[i];
}
}
int main(int argc, char **argv)
{
int numOfProc, procID;
vector<int> vect, finalVect;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numOfProc);
MPI_Comm_rank(MPI_COMM_WORLD, &procID);
MPI_Op myOp;
MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp);
for (int i = 0; i < 5; i++)
{
vect.push_back(procID);
}
finalVect.resize(vect.size());
MPI_Reduce(vect.data(), finalVect.data(), 5, MPI_INT, myOp, 0, MPI_COMM_WORLD);
if (procID == 0)
{
vector<int>::iterator it;
cout << "Final vector elements: " << endl;
for (it = finalVect.begin(); it < finalVect.end(); it++)
cout << *it << endl;
}
MPI_Finalize();
return 0;
}