【问题标题】:Memory Mapped Files, Managed Mapped File and Offset Pointer内存映射文件、托管映射文件和偏移指针
【发布时间】:2014-01-26 06:59:54
【问题描述】:

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

例如,首先映射 1 gb 部分用于写入,然后将其刷新到硬盘驱动器获取一个新部分,依此类推,而读取器应用程序映射文件的不同部分并在不更改任何内容的情况下进行读取操作(无需编辑)。

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

谁能告诉我内存映射文件和托管映射文件有什么区别以及它们的用途是什么?

如果可能的话,一些示例代码会非常适合这些和 Offset_ptr。

真的谢谢你...

【问题讨论】:

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


    【解决方案1】:

    您可以使用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的sparse文件。提交的实际大小取决于那里的一些随机性。我的运行结果大约为 1.1G:

    $ du -shc --apparent-size demo.db 
    50G demo.db
    
    $ du -shc demo.db 
    1,1G    demo.db
    

    希望对你有帮助

    【讨论】:

    • 感谢您的回答,但我不确定我是否清楚地理解了所有内容,因为它对我来说有点“高级”。所以基本上我要做的是为 1 个写入器应用程序和 8 个读取器应用程序在 sam 机器上同时工作构建一个缓冲区。写入器以 12 MB/s 的速度放置数据,读取器应用程序对缓冲区上的数据执行一些搜索和读取操作。所以我认为在磁盘上创建一个文件将某些部分映射到 RAM 以进行写入,在填充这部分后将其刷新到磁盘。但是对“如何”部分有点困惑。我至少在正确的道路上吗?
    • 只是一个补充:阅读器应用程序还应该对缓冲区上的数据进行一些搜索,以便他们也可以对其地址空间进行一些映射操作。我需要你上面说的那些隔离存储节点分配器和自适应池节点分配器吗?
    • 多个进程可以同时将同一个文件(区域)映射到它们的进程空间中。这就是您需要同步的原因(我的示例中的命名互斥锁)。无需刷新/读取即可让其他进程看到它。文件支持(仅)用于持久性。
    猜你喜欢
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2018-01-26
    • 1970-01-01
    • 2010-11-01
    • 2011-05-14
    • 2016-12-08
    相关资源
    最近更新 更多