Boost.MPI, Serializationで動的確保した配列がメンバに含まれるクラスインスタンスをシリアライズして送る.

できるのかと思ってたんですが, Boost.Serialization のチュートリアルちゃんと読んだら書いてありました.

Serialization

配列のサイズが分かっていればできそうです.

(2013/02/11 追記) 動的確保されたメモリの場合, serialize 関数でメモリ確保は行われないため, 既に確保されている必要があります. そのため, save/load を定義して load で動的メモリ確保を行う必要があります.

#include <boost/mpi.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_free.hpp>
#include <gmp.h>

// MPI で送信するデータ
struct Hoge
{
  int size;
  double * arr;

  Hoge() : size(), arr() {}

  Hoge(int size_) : size(size_), arr() {
    arr = new double[size];
  }

  ~Hoge() {
    delete arr;
  }
};

namespace boost { namespace serialization {

// 非侵入型シリアライズ
template<class Archive>
void serialize(Archive & ar, Hoge & h, const unsigned int version)
{
  // 非侵入型の save/load を呼び出す.
  split_free(ar, h, version);
}

template<class Archive>
void save(Archive & ar, Hoge const& h, const unsigned int)
{
  ar & h.size;
  for(int i = 0 ; i < h.size ; ++i)
    ar & h.arr[i];
}

template<class Archive>
void load(Archive & ar, Hoge & h, const unsigned int)
{
  ar & h.size;
  // 本当はここで既に確保されたかや確保方法を合わせるなどが必要. (new, malloc...)
  h.arr = new double[h.size];
  for(int i = 0 ; i < h.size ; ++i)
    ar & h.arr[i];
}

} } // namespace boost::serialization

int main(int argc, char** argv)
{
  boost::mpi::environment env(argc, argv);
  boost::mpi::communicator world;

  Hoge h;

  std::srand(std::time(0));
  if(world.rank() == 0) {
    h.size = 2;
    h.arr = new double[h.size];
    for(int i = 0 ; i < h.size ; ++i) {
      h.arr[i] = double(std::rand()) / RAND_MAX;
    }
  }

  boost::mpi::broadcast(world, h, 0);

  for(int i = 0 ; i < h.size ; ++i) {
    printf("[%d] arr[%d] = %f\n", world.rank(), i, h.arr[i]);
  }
}

void ポインタのようなものにはもちろんこの書き方では使えません.

Boost.Serialization は非侵入型のシリアライズもできるので既に定義されている型にも適用できます, つまりサードパーティ製ライブラリにある型でも送信できるという訳です. もちろん全てではなくて, データ構造が分かっているものなど限定はされますが.

Boost.MPI, Boost.Serialization のおかげで結構便利ですね.