circular_buffer 和 managed_mapped_file 分段错误

Posted

技术标签:

【中文标题】circular_buffer 和 managed_mapped_file 分段错误【英文标题】:circular_buffer and managed_mapped_file segmentation fault 【发布时间】:2020-10-12 02:24:53 【问题描述】:

我正在使用 boost 1.73.0,并且正在尝试使用 circular_buffer 和 manage_mapped_file 将字符串存储在磁盘上持久化的循环缓冲区中。

我执行以下操作来创建/打开循环缓冲区:

boost::interprocess::managed_mapped_file mmf(boost::interprocess::open_or_create, "./circ_buffer.bin", 10u << 10);
typedef boost::interprocess::allocator<std::string, boost::interprocess::managed_mapped_file::segment_manager> string_allocator;
typedef boost::circular_buffer<std::string, string_allocator> circ_buf;
circ_buf* instance = mmf.find_or_construct<circ_buf>("some_name")(10, mmf.get_segment_manager());

这很好用,我可以像这样将字符串放入 circular_buffer:

for(int idx = 0 ; idx < 15; idx++) 
    std::string v = "mystring1-" + std::to_string(idx);
    instance->push_back(v);

查看原始文件(即使它是二进制文件),我确实看到了其中的字符串,所以看起来 circle_buffer 确实被持久化了。

但是,如果我尝试在另一个进程中加载​​循环缓冲区,如第一个代码 sn-p 所示,并像这样读取第一个元素:

instance->front()

我遇到了分段错误。 我知道最终我需要围绕内存访问进行同步,但这不应该是上面示例中的问题,因为在任何给定时间只有一个进程正在访问文件。

有趣的是,如果我在分配器中用 char 替换 std::string,我不会得到分段错误。 我做错了什么?

Rgds 克劳斯

【问题讨论】:

【参考方案1】:
boost::interprocess::managed_mapped_file mmf(boost::interprocess::open_or_create, "./circ_buffer.bin", 10u << 10);
typedef boost::interprocess::allocator<std::string, boost::interprocess::managed_mapped_file::segment_manager> string_allocator;
typedef boost::circular_buffer<std::string, string_allocator> circ_buf;
circ_buf* instance = mmf.find_or_construct<circ_buf>("some_name")(10, mmf.get_segment_manager());

您在共享内存中分配string 对象。但是,string 自己进行分配,而您从未告诉它使用共享内存分配器。

您可能在数据中看到 short 字符串的原因是 SSO

固定版本

Live On Coliru

#include <boost/circular_buffer.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <iostream>
#include <iomanip>
namespace bip = boost::interprocess;

namespace Shared 
    using Mem = bip::managed_mapped_file;
    using Segment = Mem::segment_manager;

    template <typename T> using Alloc = bip::allocator<T, Segment>;
    template <typename T> using Buffer = boost::circular_buffer<T, Alloc<T> >;

    using String = bip::basic_string<char, std::char_traits<char>, Alloc<char> >;
    using StringBuf = Buffer<String>;


int main() 
    using namespace Shared;
    Mem mmf(bip::open_or_create, "./circ_buffer.bin", 10U << 10);

    auto& buf = *mmf.find_or_construct<StringBuf>("some_name")(10, mmf.get_segment_manager());

    for (auto& s : buf) 
        std::cout << "Existing " << std::quoted(std::string_view(s)) << "\n";
    

    for (char const* init : "foo", "bar", 
            "some pretty long string to make sure we don't fall into SSO territory"
            "some pretty long string to make sure we don't fall into SSO territory"
            "some pretty long string to make sure we don't fall into SSO territory"
            "some pretty long string to make sure we don't fall into SSO territory"
        )
    
        buf.push_back(String(init, mmf.get_segment_manager()));
    

在第二次运行时打印:

Existing "foo"
Existing "bar"
Existing "some pretty long string to make sure we don't fall into SSO territorysome pretty long string to make sure we don't fall into SSO territorysome pretty long string to make sure we don't fall into SSO territorysome pretty long string to make sure we don't fall into SSO territory"

【讨论】:

添加固定演示coliru.stacked-crooked.com/a/afaad4154272659d

以上是关于circular_buffer 和 managed_mapped_file 分段错误的主要内容,如果未能解决你的问题,请参考以下文章

将数据读入循环缓冲区

算法 RingBuffer

使用 boost 数据结构和 nghttp2 的 C++ 程序未编译

使用仅标头库时,会增加链接器错误

management.server.port 和 management.port 属性有啥区别?

如何制作支持`<<`操作的线程安全日志类?