c++11 - 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_map
to更改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 循环返回的条目的地址,以查看它们在地址空间中的位置。ls
pmap
operator<<
使用时std::unordered_map
,我得到以下信息:
之前shrink_to_fit()
:
- 映射文件大小:1048576
- 文件映射地址范围:0x7f4f912d5000 - 0x7f4f913d5000
- 映射表项地址:0x7f4f912d5238, 0x7f4f912d5188, 0x7f4f912d51f8
所以,那里的一切看起来都很好。
之后shrink_to_fit()
:
- 映射文件大小:688
- 文件映射地址范围:0x7f4f919c6000 - 0x7f4f919c62b0
- 地图入口地址:0x7f4f912d5238 (SEGV)
该映射条目完全在文件映射地址范围之外。
与使用比较boost::unordered_map
:
之前shrink_to_fit()
:
- 映射文件大小:1048576
- 文件映射地址范围:0x7fe06957f000 - 0x7fe06967f000
- 映射表项地址:0x7fe06957f2d0、0x7fe06957f290、0x7fe06957f180
都好。
之后shrink_to_fit()
:
- 映射文件大小:784
- 文件映射地址范围:0x7fe069c70000 - 0x7fe069c70310
- map入口地址:0x7fe069c702d0, 0x7fe069c70290, 0x7fe069c70180
都在映射的地址空间内。
切换回std::unordered_map
,如果我省略对 的调用shrink_to_fit()
,则文件将映射回相同的地址空间,并且一切都“正常工作”。如果被映射到不同的地址空间,那么它可能会类似地崩溃。
如果我不得不猜测,我会说这std::unordered_map
是使用常规指针,而不是offset_ptr
应该使用的 boost 进程间。
解决方案
推荐阅读
- java - 如何过滤页面流
通过 Spring Boot 应用程序中的流 Java 11 API - python - rpy2 2.9.4版安装错误使用conda
- c - 在 C 中用 memcpy 替换 for 循环不起作用
- swiftui - macCatalyst 应用程序构建但不会在 Mac 上启动
- reactjs - Apex 图表不会立即显示
- python - 尝试使用附加,当我尝试打印附加创建的列表时,它显示“无”
- css - Css - div内图像的垂直居中
- android - 活动设备数量似乎很少
- azure-cognitive-services - 为什么说话识别分数是0
- node.js - 在我们的前置 lambda 中冷启动超过 1 秒