gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 15:54:49 25 4
gpt4 key购买 nike

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

MapCreator.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;
};

同时主要代码是这样的:

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

阅读器代码如下:

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;
};

这是主要的:

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

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

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

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

boost 库版本 1.78.0

最佳答案

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

  1. 将一张大 map 分成尽可能多的小 map ,以使每张 map 所需的大小远低于 32 位系统可以处理的大小。以 < 1 GB 为例。
  2. 为您的 key 创建一个 64 位哈希函数。
  3. 使用哈希值的前 32 位来选择正确的较小 map 。如果您已将大 map 拆分为 16 个较小的 map ,则只需从该 32 位值中提取一个半字节(4 位)即可进行选择。
  4. 使用实际所选 map 中哈希值的低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";

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

您还可以有一个单独的、更便宜的函数来选择较小的 map 。如果您的 Keystd::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];
}

一个实现可以像这样开始(但绝不是完整的)。我使用标准类型和容器来避免 弄乱它具体细节,但这个想法应该可行。

#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;
};

以上默认为MapOverlay将使用MapSelector std::hash<KeyType>在每个键上选择 map 。这可能比您需要的贵很多,因此您可以更快地提供一些替代品。使用 std::hash<KeyType>如果您使用不同的实现来构建它,也有点冒险。 MapSelector共享 map 的所有程序中的算法必须相同。

// a simple class to do the underlying map selection cheaper than
// std::hash<std::string> will:
struct getmap {
size_t operator()(const std::string& kt) const {
// a naive, quick and simple map selection:
if(kt.empty()) return 0;
return kt[0];
}
};

int main() {
MapOverlay<std::string, std::string, 16, getmap> mo; // 16 small maps

mo["apa"] = "bepa"; // this will be stored in one map
mo["foo"] = "bar"; // and this in another

for(auto&[k, v] : mo) std::cout << k << " = " << v << '\n';

auto it = mo.find("foo");
if(it != mo.end()) std::cout << it->first << " = " << it->second << '\n';
}

Demo

关于c++ - 共享内存分配 > 2GB(需要链接到 VB6 使用的 32 位 DLL),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71696898/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com