2013-03-24 3 views
7

boost::interprocess::map과 같은 컨테이너에 std::string 키와 큰 struct 값을 넣는 데 관련된 힙과 by-value-by-by-reference 의미에 대해 약간 혼란 스럽습니다. 여기 부울 :: 프로세스 간 맵에 저장된 값 요소로 다시 캐스트 할 수있는 불투명 한 핸들 (void * 또는 dword)을 어떻게 반환 할 수 있습니까?

내 상황, 어떤 형식 정의는 내가 사용하고 있습니다 :

AreaValueType A(areaKey, arearec); 
anAreaMap->insert(A); 
: 나는 (표준에 대한 형식 정의 :: 쌍) AreaValueType를 삽입하고있어 어떻게

다음
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; 

입니다

위의 코드는 로컬 (비공유 메모리) 스택의 std :: pair 인 A를 공유 메모리 영역에 복사한다고 생각합니다. boost :: interprocess :: map 내에서 공유 메모리 영역에 대한 핸들을 얻을 수 있습니까? 아니면 전체 레코드를 반입하고 전체를 저장하는 것으로 제한됩니까? (다른 말로하면, 구조체를 부스트 간 프로세스 맵에 저장 한 다음 해당 레코드 내의 단일 바이트를 업데이트 할 수 있습니까? 아니면 완전히 새로운 DATA_AREA_DESC 구조체의 모든 바이트를 대체하여 전체 레코드 만 업데이트해야합니까? 바이트)

일부 추가 설명 :.

  1. 내가 내부적으로 C를 사용 ++ 및 부스트 :: 간 ::지도를 일반 오래된 ANSI C DLL 수출 API를 가지고있다. 이 함수는지도에 항목을 만든 다음 핸들을 반환합니다. 어떻게하면 boost :: interprocess :: map에 무엇인가를 삽입 한 다음 non-C++ 사용자에게 그 엔티티에 대한 핸들을 반환 할 수 있습니다. void* 또는 unsigned long으로 캐스트하는 것이 좋습니다. 내가 할 수있는 것만 큼 std :: string 키 값을 찾아 공유 메모리에서 내용을 가져오고 새 레코드를 메모리에 씁니다. 나는 대신에 공유 메모리 객체에 대한 참조를 유지할 수 있기를 바란다.

  2. 내가 직접 할 수 없다면 간접적으로 어떻게 할 수 있습니까? 비공유 메모리 std :: vector를 유지하고 비공유 메모리 std :: string을 할당하여 std :: string 인 areaKey의 값을 할당 한 다음 의 캐스트를 수행합니다. 항목을 std::string으로 다시 가져온 다음이를 사용하여 공유 메모리 영역에서 레코드를 가져옵니다. 그 모든 것은 너무 초보적인 것에 꼭 필요한 것보다 더 많은 일처럼 보입니다. 어쩌면 boost :: interprocess :: map이 내 요구 사항에 적합한 선택이 아닐까요?

무엇을 시도 했습니까? 이것은 컴파일되지만,이 권리를 제대로 수행하고 있는지 전혀 알 수 없습니다. 어떻게 든 나는 즉시과 같이 해당 주소를 복용 후 ::iteratorfind에서 반환 된 역 참조, 내부 추한 느낌 :

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

업데이트 위의 작품. 그러나 아래 답변에있는 매우 합리적인 충고는 작동하지 않습니다. boost :: interprocess :: string을 사용하면 런타임에 완전하고 완전히 실패하고 충돌이 발생합니다. Boost의 작성자가 std :: string을 특별히 코딩하지 않는 이상 작업 할 권한이없는 std :: string을 사용하면 실제로 실제로 잘 작동합니다. handle가 공유 메모리에 std::pair에 대한 포인터 있어야하는 경우

+0

글쎄, find() 대신 at()를 사용하면 역 참조가 없을 것입니다. – EHuhtala

+0

당신이 옳다고 생각합니다. –

답변

1

다음 코드는이 areaKey지도에 있음을 알고 를 제공 작동합니다. 명시 적 캐스트가 필요하지 않은 경우 (그리고 캐스트 한 경우 static_cast<void*>()이 선호 됨)를 제외하고는 아무 문제가 없습니다.

나는 boost::interprocess을 사용하지 않았지만 boost::interprocess::string 또는 std::basic_string을 키에 기본이 아닌 할당자를 사용해야합니다. boost::interprocess이 두렵지 만 않으면 std::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; 
} 

실행은 새로운 공유 메모리 세그먼트를 생성하고 기존의 공유 메모리 세그먼트를 열려면 적어도 하나 개의 인수를하기를 (A 인수가없는 호출이 이미 실행되고 있어야합니다). 두 경우 모두 프로그램은 stdin에서 키를 반복적으로 읽고 항목을지도에 삽입하고 내용을 stdout에 작성합니다.

+0

프로세스간에 유형이 지정되지 않은 값을 공유 할 필요가 없습니다. 단일 클라이언트 또는 서버 내에 유형이 지정되지 않은 API를 제공하고 Boost C++ API를 내부적으로 사용해야합니다.이 API는 DLL 인터페이스의 경우 Plain Old C로 플랫 화됩니다 ABI (응용 프로그램 바이너리 인터페이스) 목적. –

+0

나는 핸들을 위해 평범한 오래된'void * '가 필요하다는 것을 알고있다. 내 두 번째 단락에서 말하고자했던 것은 문자열 키가 프로세스 전체에서 유효하지 않으면 내부 맵이 프로세스를 공유하는 프로세스에서 올바로 작동하지 않는다는 것입니다.이 프로세스가 std :: 문자열'. 즉, 맵에서 값을 검색하려고하는 두 개의 프로세스 또는 값과 다른 읽기 값을 삽입하는 프로세스가있는 경우이 프로세스는 일반적으로'std :: string'을 맵 키로 사용하지 않을 것입니다. 이 기능이 필요하지 않다면지도가 공유되는 이유를 알 수 없다고 생각합니다. – rhashimoto

+0

부스트 MAP 타입 ('boost :: interprocess :: map')은'boost :: interprocess :: map '을 사용해야합니다. 나는 그것을 생각하지 않았기 때문에 팁을 고맙게 생각한다. –