7

のようなコンテナーにstd::stringキーと大きな値を入れる際のヒープと、値渡しと参照渡しのセマンティクスに少し混乱しています。structboost::interprocess::map

これが私の状況と、私が使用しているいくつかのtypedefです:

typedef std::string     AreaKeyType;     
typedef DATA_AREA_DESC          AreaMappedType; // DATA_AREA_DESC is a big struct.
typedef std::pair<const AreaKeyType, AreaMappedType> AreaValueType;
typedef boost::interprocess::allocator<AreaValueType, boost::interprocess::managed_shared_memory::segment_manager> AreaShmemAllocator;
typedef boost::interprocess::map<AreaKeyType, AreaMappedType, std::less<AreaKeyType>, AreaShmemAllocator> AreaMap;

AreaValueType (std::pair の typedef) を挿入する方法は次のとおりです。

 AreaValueType A(areaKey, arearec);
 anAreaMap->insert(A); 

上記のコードは、ローカル (非共有メモリ) スタックの std::pair である A を共有メモリ領域にコピーすると思います。boost::interprocess::map 内のその共有メモリ領域へのハンドルを取得できますか?それとも、そのレコード全体を取得して全体を保存することに制限されていますか? (つまり、構造体のようなものをブースト インタープロセス マップに格納してから、そのレコード内の 1 バイトを更新できますか、または DATA_AREA_DESC 構造体のすべてのバイトを完全に新しいものに置き換えて、レコード全体を更新するだけでよいですか?バイト)

さらなる説明:

  1. 内部で C++ と Boost::interprocess::map を使用するプレーンな古い ANSI C DLL エクスポート API があります。この関数は、マップ内にアイテムを作成し、ハンドルを返すことが期待されています。boost::interprocess::map に何かを挿入し、そのエンティティへのハンドルを非 C++ ユーザーに返すにはどうすればよいですvoid*unsigned long? 私ができることは、 std::string キー値を調べて共有メモリから何かをフェッチし、新しいレコードをメモリに書き込むことだけです。代わりに、共有メモリ オブジェクトへの参照を維持できるようにしたいと考えています。

  2. 直接できない場合、間接的にはどうすればよいでしょうか。非共有メモリ std::vector を保持し、areaKey の値 (std::string) を保持する非共有メモリ std::string を割り当ててから、void*アイテムのキャストを実行できると思います。に戻りstd::string、それを使用して共有メモリ領域からレコードをフェッチします。それはすべて、非常に基本的なものに厳密に必要な作業よりも多くの作業のように思えます. たぶん、boost::interprocess::map は私の要件にとって正しい選択ではないでしょうか?

私は何を試しましたか?これはコンパイルされますが、これを正しく行っているかどうかはわかりません。::iteratorどういうわけか、返された fromを逆参照しfind、すぐに次のようにそのアドレスを取得するのが醜い気がします:

void ** handle; // actually a parameter in my api.
*handle = (void*)&(*anAreaMap->find(areaKey));

更新上記は機能します。ただし、以下の回答の非常に賢明なアドバイスは機能しません。boost::interprocess::string を使用すると、実行時に完全な失敗とクラッシュが発生します。Boost の作成者が std::string サポートをコーディングしない限り、std::string を使用する権利はありませんが、実際にはうまく機能します。

4

1 に答える 1

1

が共有メモリ内handleへのポインタであると想定されている場合、それがマップ内にあることがわかっていれば、コードは機能します。明示的なキャストが必要ないことを除けば、何も問題はありません (キャストを行う場合は、キャストが推奨されます)。std::pairareaKeystatic_cast<void*>()

私は使用していませんが、キーにデフォルト以外のアロケーターを使用するboost::interprocess必要があると思います。内部で特別なことをしない限り、 usingはローカル メモリ (文字列バッファ用) へのポインタを共有メモリに配置しますが、これは別のプロセスでは意味がありません。boost::interprocess::stringstd::basic_stringboost::interprocessstd::string

以下は、文字列キーを持つマップを使用するテスト プログラムです。

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace bi = boost::interprocess;

#define SHARED_STRING 1 // set to 1 for interprocess::string, 0 for std::string
static const char *SHARED_MEMORY_NAME = "MySharedMemory";
static const char *SHARED_MAP_NAME = "MySharedMap";

int main(int argc, char *argv[]) {
#if SHARED_STRING
   typedef bi::allocator<char, bi::managed_shared_memory::segment_manager> CharAllocator;
   typedef bi::basic_string<char, std::char_traits<char>, CharAllocator> Key;
#else
   typedef std::allocator<char> CharAllocator;
   typedef std::basic_string<char, std::char_traits<char>, CharAllocator> Key;
#endif

   typedef int Mapped;
   typedef std::pair<const Key, Mapped> Value;
   typedef bi::allocator<Value, bi::managed_shared_memory::segment_manager> MapAllocator;
   typedef bi::map<Key, Mapped, std::less<Key>, MapAllocator> Map;

   bi::managed_shared_memory *segment;
   Map *map;
   if (argc <= 1) {
      // Create new shared memory segment.
      bi::shared_memory_object::remove(SHARED_MEMORY_NAME);
      segment = new bi::managed_shared_memory(bi::create_only, SHARED_MEMORY_NAME, 65536);

      MapAllocator mapAllocator(segment->get_segment_manager());
      map = segment->construct<Map>(SHARED_MAP_NAME)(std::less<Key>(), mapAllocator);
      assert(map);
   }
   else {
      // Open existing shared memory segment.
      segment = new bi::managed_shared_memory(bi::open_only, SHARED_MEMORY_NAME);

      map = segment->find<Map>(SHARED_MAP_NAME).first;
      assert(map);
   }

#if SHARED_STRING
   CharAllocator charAllocator(segment->get_segment_manager());
#else
   CharAllocator charAllocator;
#endif
   while (true) {
      std::string input;
      if (!getline(std::cin, input))
         break;

      map->insert(std::make_pair(Key(input.begin(), input.end(), charAllocator), 0));

      BOOST_FOREACH(const Value& value, *map)
         std::cout << boost::format("('%s',%d)\n") % value.first % value.second;
   }

   delete segment;
   bi::shared_memory_object::remove(SHARED_MEMORY_NAME);

   return 0;
}

新しい共有メモリ セグメントを作成するには引数なしで実行し、既存の共有メモリ セグメントを開くには少なくとも 1 つの引数を指定して実行します (引数なしの呼び出しは既に実行されている必要があります)。どちらの場合も、プログラムは からキーを読み取り、stdinエントリをマップに挿入し、内容を に書き込みますstdout

于 2013-03-31T17:40:39.640 に答える