内存映射文件、托管映射文件和偏移指针。

3
我对Boost库(Windows版本)的术语有点困惑。我想做的只是在硬盘上创建一个文件(一个大于50 GB的文件),然后分别进行写和读操作的映射。
例如,首先将1 GB的一部分映射到写入,然后将其刷新到硬盘,取出新的一部分,以此类推。而读取应用程序则映射文件的不同部分,并进行阅读操作而不更改任何内容(无编辑)。
我正在阅读boost的文档(我们允许使用1.47.0版本),但我不太明白何时使用“内存映射文件”方法,例如:file_mapping、managed_region以及“管理映射文件”:basic_managed_mapped_file和Offset_Ptr等。
请问有人能告诉我内存映射文件和管理映射文件之间的区别以及它们的用途是什么吗?
如果可能的话,请提供一些关于这些的示例代码以及Offset_ptr。
非常感谢...
1个回答

4
您可以使用managed_mapped_file来透明地从内存映射文件中分配内存。这意味着在实际操作中,您通常不需要划分内存区域。它们都是虚拟内存,所以换页会在需要时加载正确的位。显然,如果存在大量的碎片或访问“跳跃”,则分页可能会成为性能瓶颈。在这种情况下,请考虑将其细分为池并从中分配。_

编辑刚刚注意到,Boost IPC在隔离存储节点分配器自适应池节点分配器下提供了支持。此外,还有关于这些存储池实现的说明在这里

这是一个简单的起点,创建一个50GB的文件并将一些数据放入其中:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>

namespace bip = boost::interprocess;
using mutex_type    = bip::named_mutex;

struct X
{
    char buf[100];
    double rate;
    uint32_t samples[1024];
};

template <typename T> using shared_alloc  = bip::allocator<T,bip::managed_mapped_file::segment_manager>;
template <typename T> using shared_vector = boost::container::vector<T, shared_alloc<T> >;
template <typename K, typename V, typename P = std::pair<K,V>, typename Cmp = std::less<K> >
                      using shared_map    = boost::container::flat_map<K, V, Cmp, shared_alloc<P> >;

using shared_string = bip::basic_string<char,std::char_traits<char>,shared_alloc<char> >;
using dataset_t     = shared_map<shared_string, shared_vector<X> >;

struct mutex_remove
{
    mutex_remove() { mutex_type::remove("7FD6D7E8-320B-11DC-82CF-39598D556B0E"); }
    ~mutex_remove(){ mutex_type::remove("7FD6D7E8-320B-11DC-82CF-39598D556B0E"); }
} remover;

static mutex_type mutex(bip::open_or_create,"7FD6D7E8-320B-11DC-82CF-39598D556B0E");

static dataset_t& shared_instance()
{
    bip::scoped_lock<mutex_type> lock(mutex);
    static bip::managed_mapped_file seg(bip::open_or_create,"./demo.db", 50ul<<30); // "50Gb ought to be enough for anyone"

    static dataset_t* _instance = seg.find_or_construct<dataset_t>
        ("DATA")
        (
         std::less<shared_string>(), 
         dataset_t::allocator_type(seg.get_segment_manager())
        );

    static auto capacity = seg.get_free_memory();
    std::cerr << "Free space: " << (capacity>>30) << "g\n";

    return *_instance;
}

int main()
{
    auto& db = shared_instance();

    bip::scoped_lock<mutex_type> lock(mutex);
    auto alloc = db.get_allocator().get_segment_manager();

    std::cout << db.size() << '\n';

    for (int i = 0; i < 1000; ++i)
    {
        std::string key_ = "item" + std::to_string(i);
        shared_string key(alloc);
        key.assign(key_.begin(), key_.end());
        auto value = shared_vector<X>(alloc);
        value.resize(size_t(rand()%(1ul<<9)));
        auto entry = std::make_pair(key, value);

        db.insert(std::make_pair(key, value));
    }
}

请注意,它写入了一个50G的稀疏文件。实际提交的大小取决于一些随机因素。我的运行结果大约是1.1G:
$ du -shc --apparent-size demo.db 
50G demo.db

$ du -shc demo.db 
1,1G    demo.db

希望这能帮到您。

谢谢您的回答,但是我不确定我是否完全理解了,因为对我来说有点“高级”。所以基本上我想做的是为一个写入应用程序和8个读取应用程序在同一台机器上同时工作构建一个缓冲区。写入者每秒放入12 MB 的数据,而读取应用程序则在缓冲区上执行一些搜索和读取操作。因此,我想创建一个文件,在磁盘上映射一些部分到 RAM 以进行写入,填充此部分后将其刷新到磁盘。但是我对“如何”部分有点困惑。至少我走在正确的路上吗? - user2955554
只是补充一下:阅读器应用程序也应该在缓冲区上进行一些搜索,因此它们可能需要在其地址空间上执行一些映射操作。我是否需要上面提到的那些分离存储节点分配器和自适应池节点分配器? - user2955554
多个进程可以同时将同一个文件(区域)映射到它们的进程空间中。这就是为什么需要同步(在我的示例中使用命名互斥量)。其他进程看到它时无需刷新/读取。文件支持只是为了持久性。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接