Managed External Bufferは便利かも?

久しぶりに更新。Boost.interprocessの話です。またもやドキュメントパラパラ見てたら結構使えそうなやつが出てきたのでメモ。

Managed External Buffer

"様々な状況でSimpleなオブジェクト、STLと同じようなコンテナや文字列、
あとは何かしらのバッファが欲しいときがある。
これは1つの大きなstatic buffer領域を使ってそれらの補助を行う。"
Boost.interprocess Document P.87 より、超意訳

・・・だとか書かれてると思います。多分。1つの大きなstatic buffer領域を扱ってそこに複雑なコンテナを作れたり、あとは領域をコピーしたり複製作ったりできるそうです。これもManaged Memory Segmentsの1つです。basic_managed_external_bufferクラステンプレートで、テンプレート引数はManaged Shared Memoryと同じようです。面倒なのでtypedef中の引数指定は省略。

template <
    class CharType,
    class MemoryAlgorithm,
    template<class IndexConfig> class IndexType
>
class basic_managed_external_buffer;

typedef basic_managed_external_buffer<char,   ...> managed_external_buffer;
typedef basic_managed_external_buffer<wchar_t ...> wmanaged_external_buffer;

2010-12-25 - krustf の雑記のManaged Mapped Fileを使っているところを改編してManaged External Bufferを使ったコードにしてみます。たぶんコンテナを使ってる部分などはほとんど変わらないはずです。

#include <boost/interprocess/managed_external_buffer.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/aligned_storage.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/algorithm/generate.hpp>
#include <iostream>

void manage_buffer_test();

int main()
{
    try {
        manage_buffer_test();
    } catch( std::exception& e ) {
        std::cerr << e.what() << std::endl;
    }
}

void manage_buffer_test()
{
    namespace bip = boost::interprocess;

    // 固定領域の確保
    static const std::size_t MemorySize = 65536;
    static boost::aligned_storage<MemorySize>::type static_buffer;

    typedef bip::allocator<int,bip::managed_external_buffer::segment_manager> allocator_int_t;
    typedef bip::vector<int,allocator_int_t> int_vector_t;
    {
        bip::managed_external_buffer mbuffer(bip::create_only,&static_buffer,MemorySize);

        const allocator_int_t my_allocator(mbuffer.get_segment_manager());
        int_vector_t& mbuffer_vect = *(mbuffer.construct<int_vector_t>("MyVector")(my_allocator));
        BOOST_ASSERT(&mbuffer_vect == mbuffer.find<int_vector_t>("MyVector").first);

        // 適当に出力
        mbuffer_vect.resize(10);
        boost::generate(mbuffer_vect,[](){ return 42; });
    }
    {
        // 固定領域を他のバッファへコピーして開くこともできる
        static boost::aligned_storage<MemorySize>::type static_buffer2;
        std::memcpy(&static_buffer2,&static_buffer,MemorySize);

        bip::managed_external_buffer mbuffer(bip::open_only,&static_buffer2,MemorySize);

        // 検索して、vectorの中身を表示してみる
        int_vector_t const& mbuffer_vect = *(mbuffer.find<int_vector_t>("MyVector").first);
        BOOST_ASSERT(&mbuffer_vect);
        boost::for_each(mbuffer_vect,[](int i){ std::cout << i << " "; });
    }
}

結構簡単ですね。メモリに直接書いてるのでflushする必要ないですし、必要に応じてこのバッファデータをコピーすることもできます。ドキュメントのP.89の末尾を見てみると、"組み込みシステム開発においてメモリ断片化を防いで小さなデータベースを作るのに役立つ場合があります。"と言った内容が書かれています。確かにメモリが制限されているようなところで重宝しそうです。
わざわざプロセス間とかで共有を図りたいわけではない場合が多いのでShared Memoryは微妙ですし、速度が気になるのでFile Mappingも微妙ですし。1つのプログラム中で使用するメモリを制限する際には非常に重要な役割を持ちそうですね。ゲーム内で使用メモリを制限する場合などにこれを使ってみると少しは手軽に制限がかけられそうな気がします。