首页 > 解决方案 > 如何搜索存储在 Boost::managed_shared_memory 段中的 Boost::interprocess::map 作为 open_read_only?

问题描述

我有一个 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

解决方案


您永远不会检查指针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 以实现可重用性
  • 请注意,使用.atafter.find非常浪费。这特别浪费,因为您使用 /shared/ 字符串作为键。

智能高效

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

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

住在科利鲁

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

考虑范围分配器

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");

再次看到它住在 Coliru 上


推荐阅读