2013-03-24 14 views
7

anahtar ve struct büyük bir değerin boost::interprocess::map gibi bir kaba yerleştirilmesiyle ilgili yığın ve by-value-göre-anlam semantiği tarafından biraz kafam karıştı. İşte Bir destek :: süreçler arası eşlemede saklanan bir değer öğesine geri dönüştürülebilen bir opak tutamacı (void * veya dword) nasıl döndürebilirim?

benim durumdur ve bazı typedefs kullanıyorum:

AreaValueType A(areaKey, arearec); 
anAreaMap->insert(A); 
: I (std için bir typedef :: çiftinin) AreaValueType takacağım nasıl

İşte
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; 

olduğunu

Yukarıdaki kod kopyaları yerel (paylaşılmayan bellek) yığınımdaki bir std :: çifti olan bir paylaşılan bellek alanına kopyalar. Boost :: interprocess :: map içindeki paylaşımlı bellek alanına bir tutamaç alabilir miyim ya da bu kaydı geri almak ve tamamını saklamakla sınırlı mıyım? (Başka bir deyişle, bir yapı ara işlem haritasına bir yapı gibi bir şey kaydedebilir ve daha sonra bu kaydın içindeki tek bir baytı güncelleyebilir veya tüm kayıtların tümüyle yeni bir DATA_AREA_DESC yapısında yer değiştirerek tüm kaydı güncelleştirmek zorunda mıyım? bayt)

Bazı Daha fazla açıklamanın:.

  1. içeriden C harflerini ++ ve Boost :: süreçler arası :: harita bir düz eski ANSI C DLL ihracat api var. Bu işlevin haritada bir öğe oluşturması ve ardından bir tanıtıcı döndürmesi beklenir. Boost :: interprocess :: haritasına bir şey nasıl ekleyebilirim ve daha sonra bu öğeye bir tanıtıcıyı C++ olmayan kullanıcılara, tercihen void* veya unsigned long'a dönüştürebilir miyim? Yapabileceğim tek şey, std :: string anahtar değerine bakarak paylaşılan belleğe bir şeyler almak ve belleğe yeni bir kayıt yazmak. Bunun yerine, paylaşılan bellek nesnesine bir referans tutabilmek isterim.

  2. Bunu doğrudan yapamazsam, dolaylı olarak nasıl yapabilirim? Paylaşımlı olmayan bir std :: vektörünü saklayabilirim ve paylaşılamayan bir bellek std :: string'i bir std :: string olan fieldKey değerini tutup, sonra da void* dökümünü yapabilirim Öğeyi std::string'a geri döndürün ve sonra paylaşılan hafıza alanından bir kaydı almak için bunu kullanın. Her şey çok basit bir şey için kesinlikle gerekli olması gerekenden daha fazla iş gibi görünüyor. Belki destek :: interprocess :: harita gereksinimleri için doğru seçim değil mi?

Ne denedim? Bu, derler, ancak bu hakkı kullanıp kullanmadığımı hiç bilmiyorum. Her nasılsa ben hemen şöyle adresini alarak daha sonra bir ::iteratorfind döndü dereferencing ve iç çirkin hissediyorum:

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

Güncelleme yukarıdaki eserler. Aşağıdaki cevabın çok mantıklı tavsiyesi, ancak çalışmaz. Boost :: interprocess :: string kullanımı, tam ve toplam başarısızlıkla sonuçlanır ve çalışma zamanında kilitlenir. Boost kodlu std :: string desteğinin yazarları özellikle çalışmadığı sürece çalışma hakkı olmayan std :: string'in kullanılması gerçekten işe yarıyor. handle paylaşılan hafızada std::pair bir gösterici olması gerekiyordu Eğer

+0

iyi, find() yerine at() kullanabilirsiniz, sonra dereferencing olmayacaktır :) – EHuhtala

+0

Sanırım haklısınız. –

cevap

1

sonra kod areaKey haritası olduğunu biliyoruz sağlanan çalışacaktır. Açık bir dökümana ihtiyacınız olmadığından bununla ilgili yanlış bir şey yok (ve eğer cast yaparsanız static_cast<void*>() tercih edilir).

boost::interprocess kullanmamıştım, ancak anahtarınız için varsayılan olmayan bir ayırıcı ile boost::interprocess::string veya std::basic_string kullanmanız gerekecek. boost::interprocess, kapağın altında bir şey yapmazsa, std::string kullanarak yerel belleğe (dize arabelleği için) başka bir işlemde anlamlı olmayacak şekilde paylaşılan belleğe bir işaretçi koyacaktır. İşte

dize anahtarları bir harita kullanan bir test programı: hayır argümanlarla

#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; 
} 

Run it yeni bir paylaşılan bellek parçası oluşturulamadı ve varolan paylaşılan bellek segmenti açmak için en az bir bağımsız değişkenle (a argüman çağırma işlemi zaten çalışıyor olmalıdır). Her iki durumda da program yinelemeli olarak stdin anahtarını okuyacaktır, haritaya bir giriş ekleyecektir ve içeriği stdout'a yazacaktır.

+0

İşlemler arasında türlenmemiş değerleri paylaşmam gerekmez, yalnızca tek bir istemci veya sunucu içinde bir türlenmemiş API sağlamanız gerekir ve dahili olarak DLL arabirimi için Düz Eski C'ye kadar düzleştirilmiş olan Boost C++ API'lerini kullanacaktır ABI ('Uygulama ikili arayüzü') amaçları. –

+0

Anlayışınız için sadece düz bir eski 'void *' ye ihtiyacınız olduğunu anlıyorum. İkinci paragrafımda söylemeye çalıştığım şey, dahili anahtarınızın, dize anahtarı işlemlerde geçerli olmadığı sürece paylaştığınız işlemler arasında doğru bir şekilde çalışmadığı ve bir std :: string'. Yani, haritada değerlere bakmaya çalışan iki işleminiz varsa ya da değerlerin ve başka bir okuma değerinin eklendiği bir işlem varsa, bu muhtemelen harita anahtarı olarak sıradan bir 'std :: string' ile çalışmaz. Bu yeteneğe ihtiyacınız yoksa o zaman haritanın neden paylaşıldığını anlamıyorum. – rhashimoto

+0

Artış MAP türü ('boost :: interprocess :: map') 'boost :: interprocess :: map ' kullanıyor olmalı? Bahsettiğim gibi ipucunu takdir ediyorum. –

İlgili konular