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

时间:2014-01-08 09:11:43

标签: c++ boost shared-memory memory-mapped-files interprocess

我对Boost Library(用于Windows)的术语有点困惑。我想做的只是简单;在磁盘上创建一个文件(一个大文件> 50 GB)单独为写入和读取操作做一些映射。

例如,第一张地图1 gb部分用于写作&之后,将它刷新到硬盘驱动器上取一个新的部分,依此类推,同时读取器应用程序映射文件的不同部分,并在不改变任何内容的情况下进行读取(无编辑)。

我正在阅读boost(1.47.0版本,因为我们允许使用此文档)的文档,我不明白何时使用内存映射文件方法,如:file_mapping,managed_region和托管地图文件:例如basic_managed_mapped_file和Offset_Ptr。

任何人都可以告诉我内存映射文件和托管映射文件之间的区别是什么?它们的用途是什么?

如果可能的话,一些示例代码对这些以及Offset_ptr也会高度关注。

非常感谢你......

1 个答案:

答案 0 :(得分:4)

您可以使用managed_mapped_file从内存映射文件透明地分配。

这意味着,出于所有实际目的,您通常不需要重复划分您的记忆区域。无论如何它都是虚拟内存,因此分页负责在所需的时间加载正确的位。

显然,如果有很多碎片或访问“跳转”,那么分页可能会成为性能瓶颈。在这种情况下,请考虑细分为池并从中进行分配。)_

编辑刚刚注意到Boost IPC在Segregated storage node allocatorsAdaptive pool node allocators下支持此功能。还有关于这些存储池here的实现的说明。

这是一个简单的起点,可以创建一个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

希望这有帮助