共享内存分配> 2GB(需要链接到VB6使用的32位DLL)

Dan*_*ere 2 c++ boost shared-memory visual-studio

我正在使用 C++ 中 boost 库的共享内存,我试图分配一个 unordered_map 与其他进程共享。服务器端代码如下:

地图创建器.h

//#pragma once
#pragma warning( disable :4494 )
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>

struct dataClass {
    double Somma;
    int Contatore;
};

namespace bip = boost::interprocess;
namespace bc = boost::container;
#ifdef COLIRU
using Segment = bip::managed_mapped_file;
#else
using Segment = bip::managed_shared_memory;
#endif
using Mgr = Segment::segment_manager;

template <typename T> using Alloc = bip::allocator<T, Mgr>;
using MyString = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
using KeyType = MyString;
using MappedType = dataClass;
using ValueType = std::pair<KeyType const, MappedType>;
using MySHMMap = boost::unordered_map<KeyType, MappedType, boost::hash<MyString>,
    std::equal_to<MyString>, Alloc<ValueType>>;

class MapCreator {
public:
    static constexpr int sizeDeclared = 1324*1024*1024; //< Here the problem, if i set 2000*1024*1024, the client application throw error
    MapCreator(const char* Nome) // : nameMemory(Nome)
    {
        
        nameMemory = Nome;
        remove();
        segment = Segment{ bip::create_only, nameMemory, sizeDeclared };
        
        mappa = segment.find_or_construct<MySHMMap>("MySHMMapName")(segment.get_segment_manager());
    }

    dataClass getValue(std::string key) const {
        return mappa->at(MyString(key.c_str(), segment.get_segment_manager()));
    }
    void insertValue(std::string key,dataClass value) {
        mappa->emplace(MyString(key.c_str(), segment.get_segment_manager()),
            value);
    }
    double getFreeMemory() {
        return ((double)segment.get_free_memory() / 1024 / 1024 / 1024);
    }
    long getSize() {
        return mappa->size();
    }
    void remove() {
        bip::shared_memory_object::remove(nameMemory);
    }
    double getTotalSize() {
        return (double)sizeDeclared/1024/1024/1024;
    }
    double getTotalMemory() {
        return (double)segment.get_size() / 1024 / 1024 / 1024;
    }
private:
    

    // note: declaration order defines initialization order!
    const char* nameMemory = "SharedMemoryName";

    Segment segment;//{ bip::open_or_create, nameMemory, sizeDeclared };
    MySHMMap* mappa = nullptr;
};
Run Code Online (Sandbox Code Playgroud)

同时主要代码是这样的:

#include "MapCreator.h"
int main(){
  MapCreator mappaClass("thread1");
  mappaClass.insertValue("a", dataClass{ 3.12,2123 });
}
Run Code Online (Sandbox Code Playgroud)

Reader的代码如下:

ReaderFromMemory.h

//#pragma once
#pragma warning( disable :4494 )
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>

struct dataClass {
    double Somma;
    int Contatore;
};

namespace bip = boost::interprocess;
namespace bc = boost::container;
#ifdef COLIRU
using Segment = bip::managed_mapped_file;
#else
using Segment = bip::managed_shared_memory;
#endif
using Mgr = Segment::segment_manager;

template <typename T> using Alloc = bip::allocator<T, Mgr>;
using MyString = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
using KeyType = MyString;
using MappedType = dataClass;
using ValueType = std::pair<KeyType const, MappedType>;
using MySHMMap = boost::unordered_map<KeyType, MappedType, boost::hash<MyString>,
    std::equal_to<MyString>, Alloc<ValueType>>;

class Reader {
public:
    Reader() : mappa(segment.find_or_construct<MySHMMap>("MySHMMapName")(
        segment.get_segment_manager()))

    {


    }

    dataClass getValue(const char* key) const {
        return mappa->at(MyString(key, segment.get_segment_manager())); // < Here is the error while reading
    }

private:

    // note: declaration order defines initialization order!
    static constexpr char const* nameMemory = "thread1";

    Segment segment{ bip::open_only, nameMemory };;
    MySHMMap* mappa = nullptr;
};
Run Code Online (Sandbox Code Playgroud)

这是主要的:

#include "ReaderFromMemory.h"
int main(){
  Reader reader;
  auto testValue = reader.getValue("a");
}
Run Code Online (Sandbox Code Playgroud)

所以问题是分配和读取超过2GB。

我已经尝试使用 /LARGEADDRESSAWARE 标志,但对于我正在使用的 Reader 不起作用:

Visual Studio 2022 用于在 x86 模式下编译,因为读取器是 VB6 使用的 DLL

升压库版本1.78.0

Ted*_*gmo 6

由于这应该在 32 位环境中工作,因此您可以在直接访问您现在拥有的一张地图的顶部放置一个图层。以下是该想法的概述:

  1. 将一个大映射分成所需的多个较小的映射,以使每个映射所需的大小远低于 32 位系统中可以寻址的大小。以 < 1 GB 为例。
  2. 为您的密钥创建 64 位哈希函数。
  3. 使用哈希值的前 32 位来选择正确的较小映射。如果您将大映射分成 16 个较小的映射,则只需要该 32 位值中的一个半字节(4 位)即可进行选择。
  4. 使用实际选择的映射中的哈希值的底部 32 位。
uint64_t hasher64(const KeyType& kt) {
    //...
}
namespace std {
    struct hash<KeyType> {
        size_t operator()(const KeyType& kt) const {
            return hasher64(kt) & 0xFFFFFFFF;
        }
    };
}

MySHMMap& getmap(const KeyType& kt) {
    static MySHMMap maps[16];
    return maps[(hasher64(kt) >> 32) & 0xF];
}

// ...

getmap(my_key)[my_key] = "foo";
Run Code Online (Sandbox Code Playgroud)

上面的代码对密钥进行了两次哈希处理,但会为您面临的限制提供解决方法。

您还可以有一个单独的、更便宜的功能来选择较小的地图。如果您的是 a std::string,则可以通过查看字符串中的第一个字符来进行选择。

using KeyType = std::string;

MySHMMap& getmap(const KeyType& kt) {
    static MySHMMap maps[16];
    if(kt.empty()) return maps[0];
    return maps[kt[0] & 0xF];
}
Run Code Online (Sandbox Code Playgroud)

实现可以这样开始(但绝不是完整的)。我使用了标准类型和容器,以免与细节混淆,但这个想法应该可行。

using KeyType = std::string;

MySHMMap& getmap(const KeyType& kt) {
    static MySHMMap maps[16];
    if(kt.empty()) return maps[0];
    return maps[kt[0] & 0xF];
}
Run Code Online (Sandbox Code Playgroud)

上面的默认设置MapOverlay是使用MapSelector std::hash<KeyType>每个键上的 来选择地图。这可能比您需要的要贵得多,因此您可以更快地提供一些东西作为替代方案。如果您使用不同的实现来构建它,那么使用std::hash<KeyType>也有点风险。MapSelector共享地图的所有程序中的算法必须相同

#include <unordered_map>
#include <iostream>

template<class KeyType, class MappedType, size_t MapCo,
         class MapSelector = std::hash<KeyType>>
class MapOverlay {
public:
    using MySHMMap = std::unordered_map<KeyType, MappedType>;
    using value_type = typename MySHMMap::value_type;

    struct iterator { // an iterator to iterate seamlessly over the multiple maps
        iterator(MapOverlay* mo, MySHMMap& m, typename MySHMMap::iterator c) :
            mo(mo), map(&m), it(c) 
        {
            find_non_empty(); // find the first map with values
        }

        value_type& operator*() { return *it; }
        value_type* operator->() { return &*it; }

        iterator& operator++() {
            if(it == map->end()) {
                ++map;
                it = map->begin();
            } else ++it;
            find_non_empty();
            return *this;
        }

        bool operator==(const iterator& rhs) const {
            return map == rhs.map && it == rhs.it; 
        }
        bool operator!=(const iterator& rhs) const { return !(*this == rhs); }

    private:
        void find_non_empty() { // find the next map with values
            while(it == map->end() && map != &mo->maps[MapCo-1]) {
                ++map;
                it = map->begin();
            }
        }

        MapOverlay* mo;
        MySHMMap* map;
        typename MySHMMap::iterator it;
    }; // iterator end

    // some member functions making it feel like a normal unordered_map
    MappedType& operator[](const KeyType& kt) {
        return map_lookup(kt)[kt];
    }

    iterator find(const KeyType& kt) {
        auto& m = map_lookup(kt);
        auto it = m.find(kt);
        if(it == m.end()) return end();
        return {this, m, it};
    }

    iterator begin() { return {this, maps[0], maps[0].begin()}; }
    iterator end() { return {this, maps[MapCo-1], maps[MapCo-1].end()}; }

private:
    MySHMMap& map_lookup(const KeyType& kt) {
        // call the map selector for `kt` and use `% MapCo` to get it in range
        return maps[ms(kt) % MapCo];  // ms is an instance of MapSelector
    }

    MySHMMap maps[MapCo];
    MapSelector ms;
};
Run Code Online (Sandbox Code Playgroud)

演示