2013-03-24 23 views
7

Tôi hơi bối rối bởi ngữ nghĩa heap và by-value-versus-by-reference liên quan đến việc đặt một khóa std::string và giá trị struct lớn vào một vùng chứa như boost::interprocess::map.Làm cách nào tôi có thể trả về một xử lý mờ (void * hoặc dword) có thể được đưa trở lại thành phần tử giá trị được lưu trữ trong bản đồ tăng tốc :: interprocess?

Đây là hoàn cảnh của tôi, và một số typedefs Tôi đang sử dụng:

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; 

Sau đây là cách tôi chèn AreaValueType (mà là một typedef cho std :: cặp):

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

Tôi tin rằng các bản sao mã ở trên A là một cặp std :: trên ngăn nhớ cục bộ (không chia sẻ bộ nhớ) của tôi vào một vùng bộ nhớ dùng chung. Tôi có thể có được một xử lý cho rằng khu vực bộ nhớ chia sẻ bên trong tăng :: interprocess :: bản đồ hoặc tôi giới hạn để lấy lại hồ sơ đó trở lại toàn bộ và lưu trữ toàn bộ? (Nói cách khác, tôi có thể lưu trữ thứ gì đó như cấu trúc thành bản đồ interprocess tăng cường và sau đó cập nhật một byte đơn bên trong bản ghi đó hoặc tôi chỉ phải cập nhật toàn bộ bản ghi bằng cách thay thế tất cả các byte trong cấu trúc DATA_AREA_DESC, với byte)

một số tiếp tục làm rõ.

  1. tôi có một tuổi ANSI C DLL api xuất khẩu rõ ràng rằng trong nội bộ sử dụng C++ và Boost :: interprocess :: bản đồ. Hàm này được mong đợi để tạo một mục trong bản đồ và sau đó trả về một tay cầm. Làm thế nào tôi có thể chèn một cái gì đó vào tăng :: interprocess :: bản đồ và sau đó trả về một xử lý cho thực thể đó, cho người dùng không phải C++, tốt nhất là cast void* hoặc unsigned long? Tất cả những gì tôi có thể làm là lấy nội dung từ bộ nhớ dùng chung bằng cách tra cứu giá trị std :: string key và ghi một bản ghi mới vào bộ nhớ. Thay vào đó, tôi muốn có thể giữ một tham chiếu đến đối tượng bộ nhớ dùng chung xung quanh.

  2. Nếu tôi không thể trực tiếp làm điều đó, tôi sẽ làm điều đó gián tiếp như thế nào? Tôi cho rằng tôi có thể giữ một std không chia sẻ bộ nhớ :: vector, và phân bổ một bộ nhớ không chia sẻ std :: string giữ giá trị của areaKey, đó là một std :: string, và sau đó làm một diễn viên của void* quay trở lại std::string và sau đó sử dụng nó để tìm nạp bản ghi ra khỏi vùng bộ nhớ dùng chung. Điều đó dường như có nhiều công việc hơn là cần thiết cho một thứ gì đó sơ cấp. Có thể tăng :: interprocess :: map không phải là lựa chọn đúng cho các yêu cầu của tôi?

Tôi đã thử gì? Điều này, mà biên dịch, nhưng tôi không có ý tưởng nếu tôi làm điều này đúng. Bằng cách nào đó tôi cảm thấy xấu xí bên dereferencing một ::iterator trở về từ find, và sau đó ngay lập tức lấy địa chỉ của nó như sau:

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

Cập nhật Các công trình trên. Tuy nhiên, lời khuyên rất hợp lý trong câu trả lời dưới đây KHÔNG làm việc. Sử dụng tăng :: interprocess :: chuỗi kết quả trong hoàn thành và tổng số thất bại và treo trong thời gian chạy. Sử dụng std :: string, mà không có quyền làm việc trừ khi các tác giả của Boost mã std :: string hỗ trợ đặc biệt, thực sự hoạt động tốt.

+0

tốt, bạn có thể sử dụng tại() thay vì tìm(), sau đó sẽ không có dereferencing :) – EHuhtala

+0

Tôi nghĩ rằng bạn là đúng. –

Trả lời

1

Nếu handle được coi là một con trỏ đến std::pair trong bộ nhớ chia sẻ sau đó mã của bạn sẽ làm việc cung cấp bạn biết rằng areaKey là trong bản đồ. Không có gì sai với nó, ngoại trừ bạn không cần cast rõ ràng (và nếu bạn cast thì static_cast<void*>() sẽ được ưu tiên hơn).

Tôi chưa sử dụng boost::interprocess nhưng tôi nghĩ bạn sẽ cần sử dụng boost::interprocess::string hoặc std::basic_string với trình phân bổ không mặc định cho khóa của bạn. Trừ khi boost::interprocess thực hiện điều gì đó lạ mắt dưới mui xe, sử dụng std::string sẽ đặt con trỏ vào bộ nhớ cục bộ (cho bộ đệm chuỗi) vào bộ nhớ dùng chung sẽ không có ý nghĩa trong quá trình khác.

Dưới đây là một chương trình thử nghiệm có sử dụng một bản đồ với các phím chuỗi:

#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 nó không có đối số để tạo ra một phân đoạn bộ nhớ chia sẻ mới và có ít nhất một đối số để mở một phân đoạn bộ nhớ chia sẻ hiện có (một lời gọi không đối số phải đang chạy). Trong cả hai trường hợp, chương trình sẽ lặp lại đọc một khóa từ stdin, chèn một mục nhập vào bản đồ và ghi nội dung vào stdout.

+0

Tôi không cần phải chia sẻ các giá trị untyped giữa các quy trình, tôi chỉ cần cung cấp một API không được phân loại bên trong một máy khách hoặc máy chủ duy nhất. Mục đích ABI ('Application binary interface'). –

+0

Tôi hiểu rằng bạn chỉ cần một đồng bằng cũ 'void *' cho xử lý của bạn. Những gì tôi đã cố gắng để nói trong đoạn thứ hai của tôi là bản đồ nội bộ của bạn sẽ không hoạt động chính xác trên các quá trình chia sẻ nó trừ khi khóa chuỗi của nó là hợp lệ trên các quy trình, và nó sẽ không hợp lệ nếu nó là một 'std :: string'. Tức là, nếu bạn có hai quá trình cố gắng tra cứu các giá trị trong bản đồ, hoặc một quá trình chèn các giá trị và các giá trị đọc khác, điều này có lẽ sẽ không hoạt động với một chuỗi 'std :: string' bình thường như khóa bản đồ. Nếu bạn không cần khả năng này thì tôi đoán tôi không hiểu tại sao bản đồ được chia sẻ. – rhashimoto

+0

Vì vậy, loại MAP tăng ('boost :: interprocess :: map') nên sử dụng' boost :: interprocess :: map 'phải không? Tôi đánh giá cao mẹo như tôi đã không nghĩ về nó. –