2012-12-08 7 views
7

次のようにマップ内の値は、次のとおりマップ::プロセス間

 typedef pair<MutexType, boost::interprocess::offset_ptr<void> > ValueType ; 

MutexTypeを読み出して(read_lockとWRITE_LOCKを使用して)書き込みミューテックスを含む構造そのものです。 次のように定義される:

typedef struct mutex_struct{ 
    sharable_lock<interprocess_mutex> read_lock(interprocess_mutex, defer_lock); 
    scoped_lock<interprocess_mutex> write_lock(interprocess_mutex, defer_lock); 
} MutexType; 

「サイズ」(オブジェクトの観点ので、データサイズの合計が全ボイドポインタによって指される)マップの合計サイズです。

このvoid *データが作成したこのメモリセグメントにも存在することを、どうすればできますか。既存の共有メモリ領域内でインスタンス化するにはどうすればよいですか?これを行う理由は、この大きなバッファを1回だけ割り当てることですが、オブジェクトを繰り返し削除/追加する必要があります(マップはキャッシュをモデル化します)。同じメモリセグメント内に複数のオブジェクトを割り当てる方法はまだありませんマップ内でさらに、MutexTypeペアを割り当てようとすると、 "call"演算子が提供されていないことを示すコンパイルエラーが返されます。

答えて

11

基本的には既に存在しています。共用メモリSecondValue_tに割り当てるオブジェクト・タイプを呼び出します。 ShMemAllocator_tの代わりに、SecondValue_tオブジェクトを割り当てるために異なるプロセス間アロケータ・タイプ、たとえばSecondValueAllocator_tを定義します。 ValueTypeオブジェクトをマップに挿入する場合は、ValueTypeオブジェクトの2番目の値がSecondValueAllocator_tインスタンスで割り当てられます。ここで

は、一部Interprocess reader/writer lock with Boostためmy answerのコードを使用して、完全な例である:最初の親プロセスを開始することにより

#include <cstdlib> 
#include <functional> 
#include <iostream> 
#include <string> 
#include <utility> 

#include <boost/scope_exit.hpp> 
#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/allocators/private_node_allocator.hpp> 
#include <boost/interprocess/containers/map.hpp> 
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp> 
#include <boost/interprocess/sync/scoped_lock.hpp> 
#include <boost/interprocess/sync/sharable_lock.hpp> 
#include <boost/interprocess/sync/upgradable_lock.hpp> 

#define SHARED_MEMORY_NAME "SO13783012-MyMap" 

// https://stackoverflow.com/questions/13783012/map-of-int-void-in-shared-memory-using-boostinterprocess 

using namespace boost::interprocess; 

typedef int SecondValue_t; 
typedef allocator<SecondValue_t, managed_shared_memory::segment_manager> SecondValueAllocator_t; 

typedef struct mutex_struct { 
    //... 
} MutexType; 

typedef std::pair<MutexType, SecondValueAllocator_t::pointer> ValueType; 

typedef map<int, ValueType>::value_type MyMapValueType; 
typedef allocator<MyMapValueType, managed_shared_memory::segment_manager> MyMapEntryAllocator_t; 
typedef map<int, ValueType, std::less<int>, MyMapEntryAllocator_t> MyMap_t; 

struct shared_data { 
private: 
    typedef boost::interprocess::interprocess_upgradable_mutex upgradable_mutex_type; 

    mutable upgradable_mutex_type mutex; 
    MyMap_t my_map; 

public: 
    shared_data(const MyMapEntryAllocator_t& alloc) 
     : my_map(MyMap_t::key_compare(), alloc) 
    { 
    } 

    // Tries to get the mapped value for the given key `k'. If successful, the mapped value is 
    // copied into `out' and `true' is returned. Otherwise, returns `false' and does not modify 
    // `out'. 
    bool try_get(MyMap_t::mapped_type& out, MyMap_t::key_type k) const { 
     boost::interprocess::sharable_lock<upgradable_mutex_type> lock(mutex); 
     MyMap_t::const_iterator pos = my_map.find(k); 
     if (pos != my_map.end()) { 
      out = pos->second; 
      return true; 
     } 
     return false; 
    } 

    void put(MyMap_t::key_type k, MyMap_t::mapped_type v) { 
     boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mutex); 
     my_map.insert(MyMap_t::value_type(my_map.size(), v)); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) { 
     std::cerr << "Usage: " << argv[0] << " WHICH\n"; 
     return EXIT_FAILURE; 
    } 

    const std::string which = argv[1]; 

    if (which == "parent") { 
     shared_memory_object::remove(SHARED_MEMORY_NAME); 
     BOOST_SCOPE_EXIT(argc) { 
      shared_memory_object::remove(SHARED_MEMORY_NAME); 
     } BOOST_SCOPE_EXIT_END; 
     managed_shared_memory shm(create_only, SHARED_MEMORY_NAME, 65536); 

     MyMapEntryAllocator_t entry_alloc(shm.get_segment_manager()); 
     shared_data& d = *shm.construct<shared_data>("theSharedData")(entry_alloc); 

     SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); 

     // Insert some test data. 
     SecondValueAllocator_t::pointer p; 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, -3); 
     d.put(0, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 70); 
     d.put(1, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, -18); 
     d.put(2, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 44); 
     d.put(3, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 0); 
     d.put(4, std::make_pair(MutexType(), p)); 

     // Go to sleep for a minute - gives us a chance to start a child process. 
     sleep(60); 
    } else { 
     managed_shared_memory shm(open_only, SHARED_MEMORY_NAME); 
     std::pair<shared_data *, std::size_t> find_res = shm.find<shared_data>("theSharedData"); 
     if (!find_res.first) { 
      std::cerr << "Failed to find `theSharedData'.\n"; 
      return EXIT_FAILURE; 
     } 
     shared_data& d = *find_res.first; 

     MyMap_t::mapped_type v; 
     int i = 0; 
     for (; d.try_get(v, i); ++i) { 
      std::cout << i << ": " << *v.second << '\n'; 
     } 

     // Add an entry. 
     srand(time(NULL)); 
     SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); 
     SecondValueAllocator_t::pointer p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, (rand() % 200) - 100); 
     d.put(i, v = std::make_pair(MutexType(), p)); 
     std::cout << "placed " << *v.second << " into the map.\n"; 
    } 

    return EXIT_SUCCESS; 
} 

テストそれを:

 
./SO13783012 parent 

その後いくつかの子供たち:

 
./SO13783012 child 

サンプル出力:

 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
placed 5: -63 into the map. 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
5: -63 
placed 6: -42 into the map. 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
5: -63 
6: -42 
placed 7: -28 into the map. 
+0

(私はこれがちょっと古いと知っていますが)あなたの例では、作家のロックが実際には機能しないことに気付きました。複数のwriter子を生成する場合、iの値は未定義である可能性があり、並行処理の問題のために同じ値を使用してペアを挿入しようとします - 最後のキーの後に別のエントリを追加するだけの場合 - putメソッドが集まるマップの現在のサイズを返し、size + 1に要素を挿入します。 – Steve

+0

こんにちは@スティーブ、私は私が従うか分からない。なぜ、 'i'の値は未定義ですか? –

+1

forループでは、d.try_getから値が返されなくなるまで++を数えます - 私は今10であると仮定します。後で、d.put(i、v = std :: make_pair(MutexType()、p));一方、もう1つの子書き込みプロセスがすでにマップに何かを入れている場合 - 10は重複しています。一度に1行ずつ実行する2人の子ライターが両方ともi = 10に到着するが、child1はi = 10で最初に新しいエントリを置くので、2番目の子は失敗する。それは、i = 10が書き込み/読み取りロックの外にあるからです。 – Steve

0

あなたは

typedef std::allocator< char, managed_shared_memory::segment_manager > char_alloc; 

は、この

char_alloc char_alloc_obj; 
char * ptr = new (char_alloc_obj.allocate(size)) char[size]; 
void * vptr = (void *) ptr; 

デフォルトのstd ::アロケータ<のようなあなたのメモリを割り当てる作るためにアロケータに<>

// convert an allocator<T> to allocator<U> 
template<typename U> 
struct rebind { 
    typedef Allocator<U> other; 
}; 

を再バインドを使用することができます>ステートレスです。共有メモリアロケータには状態があるので、異なる型のアロケータ間で状態をコピーする方法を理解する必要があります。