If you need to write a complex data structure to a file or via a network in MPI, then the problems will be the same; you need to extract the data into “Plain Old Data” (POD), save it, and then output it, and also print the saved data into the same structure. In general, this is called serialization.
, ++ Boost, Boost Serialization Library ; , (?) STL- .
Boost , Boost ( ) , / ; , , , . SO .
, :
#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;
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();
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;
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 - .