首页 > 解决方案 > SEGV 在shrink_to_fit() 之后使用boost 进程间分配器与std::unordered_map 一起抛出

问题描述

我将 boost-1.68 和 gcc-7.3.0 与-std=c++11. 以下代码为我抛出了一个 SIGSEGV。

该问题是由结合使用std::unordered_map与 boost 进程间shrink_to_fit()方法引起的。shared::unordered_map将类型从std::unordered_mapto更改boost::unordered_map和/或注释掉对 to 的调用shrink_to_fit()将修复代码。

我最终不打算使用std::unordered_map,但这个最小示例失败的事实让我担心我没有正确设置和/或没有正确使用分配器。

编辑:应该提到使用shrink_to_fit()对于我的目的是必要的。

任何见解将不胜感激。

#include <cstdio>
#include <iostream>
#include <unordered_map>
#include <scoped_allocator>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/unordered_map.hpp>

using std::cout;
using std::endl;

namespace shared {
    using segment_type = boost::interprocess::managed_mapped_file;
    using segment_manager = segment_type::segment_manager;

    template <typename T>
    using Alloc = boost::interprocess::allocator<T, segment_manager>;

    template <typename T>
    using ScopedAlloc = std::scoped_allocator_adaptor<Alloc<T>>;

    using string = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char>>;

    template <typename Key, typename Val, typename KHash = boost::hash<Key>, typename KEqual = std::equal_to<Key>>
    using unordered_map =
        std::unordered_map<Key, Val, KHash, KEqual, ScopedAlloc<std::pair<const Key, Val>>>;
}

struct MyStruct {
    shared::unordered_map<shared::string, int> some_map;

    MyStruct (shared::segment_manager *smgr)
    : some_map{smgr}
    { }

    friend std::ostream& operator<< (std::ostream& os, const MyStruct& m) {
        os << "{";
        for (auto& e : m.some_map) {
            os << "{\"" << e.first << "\"," << e.second << "}";
        }
        os << "}";
        return os;
    }
};

int main () {
    const char *filename = "content.bin";
    std::remove(filename);

    {
        shared::segment_type segment(boost::interprocess::create_only, filename, (1<<20));
        MyStruct *o1 = segment.construct<MyStruct>("MyStruct01")(segment.get_segment_manager());
        o1->some_map.emplace("entry_1", 1);
        o1->some_map.emplace("entry_2", 2);
        o1->some_map.emplace("entry_3", 3);
        cout << "constructed MyStruct01: " << *o1 << endl;
    }

    shared::segment_type::shrink_to_fit(filename);

    {
        shared::segment_type segment(boost::interprocess::open_read_only, filename);
        MyStruct *o1 = (segment.find<MyStruct>("MyStruct01")).first;
        cout << "      found MyStruct01: " << *o1 << endl;
    }

    cout << "completed" << endl;
    return 0;
}

编辑:我在代码中放了一些工具来做一些调查。我不会在这里包含它,但我曾经针对映射文件运行,并std::system在不同点针对进程运行。特别是,我想查看映射文件在进程地址空间中的位置。我还在方法中转储了 range-for 循环返回的条目的地址,以查看它们在地址空间中的位置。lspmapoperator<<

使用时std::unordered_map,我得到以下信息:

之前shrink_to_fit()

所以,那里的一切看起来都很好。

之后shrink_to_fit()

该映射条目完全在文件映射地址范围之外。

与使用比较boost::unordered_map

之前shrink_to_fit()

都好。

之后shrink_to_fit()

都在映射的地址空间内。

切换回std::unordered_map,如果我省略对 的调用shrink_to_fit(),则文件将映射回相同的地址空间,并且一切都“正常工作”。如果被映射到不同的地址空间,那么它可能会类似地崩溃。

如果我不得不猜测,我会说这std::unordered_map是使用常规指针,而不是offset_ptr应该使用的 boost 进程间。

标签: c++11boostunordered-mapallocatorboost-interprocess

解决方案


推荐阅读