【问题标题】:How do I search a Boost::interprocess::map stored within a Boost::managed_shared_memory segment as open_read_only?如何搜索存储在 Boost::managed_shared_memory 段中的 Boost::interprocess::map 作为 open_read_only?
【发布时间】:2021-12-24 07:38:20
【问题描述】:

我有一个 Boost:interprocess::unordered_map,它有一个字符串类型的键和一个字符串类型的值。该映射存储在 managed_shared_memory 段中。我试图限制对这些段的访问,因此该段是使用 rw-rw-r-- 创建的。这个想法是所有者和相关组将具有读/写访问权限,而“其他”将被限制为只读。

如果我 open_read_only 并手动遍历地图,这可以正常工作。所有数据都存在于各个进程中。我在尝试使用 mymap->find() 或 mymap->at() 时遇到了问题,因为这两个函数都需要传递 basic_string(带分配器)。

当我尝试创建用于 find() 或 at() 的 basic_string 时,出现访问冲突错误。

char_string tmpKey(searchKey, alloc_inst); // Access violation crash.

有没有办法在没有 basic_string 的情况下使用 find() 或 at()?还是有更好的方法来解决这个问题?

标题

typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::container::basic_string<char, std::char_traits<char>, CharAllocator> char_string;
typedef char_string KeyType;
typedef char_string MappedType;
typedef std::pair<const char_string, char_string> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::unordered_map<KeyType, MappedType, boost::hash<KeyType>, std::equal_to<KeyType>, ShmemAllocator> MyShmMap;

主要

managed_shared_memory segment(open_read_only, "segment_name");
MyShmMap* mymap = segment.find<MyShmMap>("segment_name").first;
CharAllocator alloc_inst(segment.get_segment_manager());
char_string tmpKey(searchKey, alloc_inst); // Access violation crash.
MyShmMap::iterator it = mymap->find(tmpKey);
if (it != mymap->end()) {
  auto value = mymap->at(tmpKey);
  // etc

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

    你永远不会检查指针 mymap 是否为空。

    如果我们确定它存在,首先执行这个(一次):

    // assuming this exists
    Segment s(bip::open_or_create, "segment_name", 10 * 1024);
    s.find_or_construct<MyShmMap>("segment_name")(s.get_segment_manager());
    

    然后一切正常:Live On Coliru

    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/containers/string.hpp>
    #include <boost/unordered_map.hpp>
    #include <boost/functional.hpp>
    
    namespace bip = boost::interprocess;
    namespace bc  = boost::container;
    
    using Segment = bip::managed_shared_memory;
    using Mgr     = Segment::segment_manager;
    
    template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
    template <typename K, typename V>
    using UnorderedMap = boost::unordered_map<K, V, boost::hash<K>, //
                                              std::equal_to<K>,
                                              Alloc<std::pair<K const, V>>>;
    
    using String   = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
    using MyShmMap = UnorderedMap<String, String>;
    
    int main() {
        {
            // assuming this exists
            Segment s(bip::open_or_create, "segment_name", 10 * 1024);
            s.find_or_construct<MyShmMap>("segment_name")(s.get_segment_manager());
        }
    
        Segment segment(bip::open_read_only, "segment_name");
        MyShmMap* mymap = segment.find<MyShmMap>("segment_name").first;
    
        auto it = mymap->find(String("test", segment.get_segment_manager()));
        if (it != mymap->end()) {
            auto const& value = it->second;
        }
    }
    

    我也借此机会

    • 清理您的 type-def 以实现可重用性
    • 请注意,在.find 之后使用.at 非常浪费。这特别浪费,因为您使用 /shared/ 字符串作为键。

    智能高效

    您可以通过使用与字符串视图兼容的哈希/相等比较器以及使用advanced lookup:来真正提高性能:

    template <typename K, typename V, typename Hash = boost::hash<K>,
              typename EqCmp = std::equal_to<K>>
    using UnorderedMap = boost::unordered_map<K, V, //
                             Hash, EqCmp, Alloc<std::pair<K const, V>>>;
    
    using MyShmMap = UnorderedMap<String, String, boost::hash<std::string_view>, std::equal_to<void>>;
    

    Live On Coliru

    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/containers/string.hpp>
    #include <boost/unordered_map.hpp>
    #include <boost/functional.hpp>
    
    namespace bip = boost::interprocess;
    namespace bc  = boost::container;
    
    using Segment = bip::managed_shared_memory;
    using Mgr     = Segment::segment_manager;
    
    template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
    template <typename K, typename V, typename Hash = boost::hash<K>,
              typename EqCmp = std::equal_to<K>>
    using UnorderedMap = boost::unordered_map<K, V, //
                             Hash, EqCmp, Alloc<std::pair<K const, V>>>;
    
    using String   = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
    using MyShmMap = UnorderedMap<String, String, boost::hash<std::string_view>, std::equal_to<void>>;
    
    #include <string_view>
    #include <iostream>
    #include <iomanip>
    
    int main()
    {
        {
            // assuming this exists
            Segment s(bip::open_or_create, "segment_name", 10 * 1024);
    
            auto* m = s.get_segment_manager();
            s.find_or_construct<MyShmMap>("segment_name")(m) //
                ->emplace(std::piecewise_construct,          //
                          std::tuple("stuff", m),            //
                          std::tuple("lives here", m));
        }
    
        Segment segment(bip::open_read_only, "segment_name");
        MyShmMap* mymap = segment.find<MyShmMap>("segment_name").first;
        auto      hash  = mymap->hash_function();
        auto      eq    = mymap->key_eq();
    
        if (auto it = mymap->find("stuff", hash, eq); it != mymap->end()) {
            auto const& [k,v] = *it;
            std::cout << std::quoted(k.c_str()) << " -> " << std::quoted(v.c_str()) << "\n";
        }
    }
    

    打印出来的

    "stuff" -> "lives here"
    

    樱桃在上面

    为了减少分配器的丑陋,例如:

    Segment s(bip::open_or_create, "segment_name", 10 * 1024);
    
    auto* m = s.get_segment_manager();
    s.find_or_construct<MyShmMap>("segment_name")(m) //
        ->emplace(std::piecewise_construct,          //
                  std::tuple("stuff", m),            //
                  std::tuple("lives here", m));
    

    考虑scoped allocators

    template <typename T> using Alloc = bc::scoped_allocator_adaptor< //
        bip::allocator<T, Segment::segment_manager>>;
    

    现在容器在使用分配器构造时传播分配器:

    Segment s(bip::open_or_create, "segment_name", 10 * 1024);
    
    auto& m = *s.find_or_construct<MyShmMap>("segment_name")(
        s.get_segment_manager());
    
    m.emplace("stuff", "lives here");
    

    再次查看Live On Coliru

    【讨论】:

    • 感谢您的详细回复。第一部分在 String 构造函数上遇到了同样的问题(访问冲突)。但是,哈希更改解决了该问题。我假设因为它不需要分配器,所以只读模式保持快乐?另外,感谢您向我介绍范围分配器。我会阅读它们并进行测试。
    • 我不确定是什么导致了段错误。您能分享失败的最小独立示例吗?我分享了@98​​7654326@,应该很容易修改?
    猜你喜欢
    • 2019-01-23
    • 2014-05-06
    • 2012-05-20
    • 2012-08-26
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多