Я искал, чтобы отправить установленный объект, и самый близкий, который я нашел, был с вектором (это отличается и не работает с набором).
Как я могу отправить установленный объект в MPI_Send? (без использования библиотеки Boost) Кто-нибудь может привести простой пример?
Если вам нужно записать сложную структуру данных в файл или по сети в MPI, проблемы одинаковы; Вы должны извлечь данные в «Обычные старые данные» (POD), сохранить их, а затем вывести их, а также иметь возможность распаковать сохраненные данные в структуру такого же типа. В общем, это называется сериализацией.
Для любой данной структуры вы всегда можете написать свои собственные подпрограммы для этого, но в C ++ в Boost есть фреймворк, называемый Библиотека повышения сериализации для этого; это немного тяжеловесно для этого примера, но он будет работать для большинства (всех?) контейнеров STL и есть хуки для добавления поддержки ваших собственных классов.
Основной трюк с использованием Boost для этого заключается в том, что библиотеки Boost (и все примеры) позволяют очень легко записывать данные в файл, но здесь вы хотите сохранить их в памяти и отправить / получить их по сети; это означает, что нужно перепрыгнуть еще пару обручей, чтобы убедиться, что сериализация находится в массиве, к которому вы можете получить доступ. Это так ответ очень полезно в этом отношении.
Итак, полный рабочий пример выглядит так:
#include <mpi.h>
#include <set>
#include <string>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/set.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
int main(int argc,char** argv) {
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (size < 2) {
if (rank == 0)
std::cerr << "Require at least 2 tasks" << std::endl;
MPI_Abort(MPI_COMM_WORLD, 1);
}
const int lentag=0;
const int datatag=1;
if (rank == 0) {
int nums[] = {1,4,9,16};
std::set<int> send_set(nums, nums+4);
std::cout << "Rank " << rank << " sending set: ";
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
// We're going to serialize into a std::string of bytes, and then send this
std::string serial_str;
boost::iostreams::back_insert_device<std::string> inserter(serial_str);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
boost::archive::binary_oarchive send_ar(s);
send_ar << send_set;
s.flush();
int len = serial_str.size();
// Send length, then data
MPI_Send( &len, 1, MPI_INT, 1, lentag, MPI_COMM_WORLD );
MPI_Send( (void *)serial_str.data(), len, MPI_BYTE, 1, datatag, MPI_COMM_WORLD );
} else if (rank == 1) {
int len;
MPI_Recv( &len, 1, MPI_INT, 0, lentag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
char data[len+1];
MPI_Recv( data, len, MPI_BYTE, 0, datatag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
data[len] = '\0';
boost::iostreams::basic_array_source<char> device(data, len);
boost::iostreams::stream<boost::iostreams::basic_array_source<char> > s(device);
boost::archive::binary_iarchive recv_ar(s);
std::set<int> recv_set;
recv_ar >> recv_set;
std::cout << "Rank " << rank << " got set: ";
for (std::set<int>::iterator i=recv_set.begin(); i!=recv_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
}
MPI_Finalize();
return 0;
}
Бег дает:
$ mpic++ mpi-set.cxx -o mpiset -lboost_serialization
$ mpirun -np 2 ./mpiset
Rank 0 sending set: 1 4 9 16
Rank 1 got set: 1 4 9 16
Если вы действительно не хотите использовать Boost, так как вы не можете видеть непосредственно в заданной структуре данных, нет другой альтернативы, кроме как извлечь данные в массив или вектор и отправить данные таким образом:
#include <mpi.h>
#include <set>
#include <vector>
int main(int argc,char** argv) {
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (size < 2) {
if (rank == 0)
std::cerr << "Require at least 2 tasks" << std::endl;
MPI_Abort(MPI_COMM_WORLD, 1);
}
const int lentag=0;
const int datatag=1;
if (rank == 0) {
int nums[] = {1,4,9,16};
std::set<int> send_set(nums, nums+4);
std::cout << "Rank " << rank << " sending set: ";
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
// Send length, then data
int len = send_set.size();
MPI_Send( &len, 1, MPI_INT, 1, lentag, MPI_COMM_WORLD );
std::vector<int> send_vec;
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
send_vec.push_back(*i);
MPI_Send( send_vec.data(), len, MPI_INT, 1, datatag, MPI_COMM_WORLD );
} else if (rank == 1) {
int len;
MPI_Recv( &len, 1, MPI_INT, 0, lentag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
int recv_data[len];
MPI_Recv( recv_data, len, MPI_INT, 0, datatag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
std::set<int> recv_set;
for (int i=0; i<len; i++)
recv_set.insert(recv_data[i]);
std::cout << "Rank " << rank << " got set: ";
for (std::set<int>::iterator i=recv_set.begin(); i!=recv_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
}
MPI_Finalize();
return 0;
}
И бег дает:
$ mpicxx -o mpisetvector mpi-set-vector.cxx
$ mpirun -np 2 mpisetvector
Rank 0 sending set: 1 4 9 16
Rank 1 got set: 1 4 9 16
Но на самом деле, если вы собираетесь делать это и с другими типами объектов, Boost — это то, что вам нужно.