【问题标题】:Vector of string shared memory map字符串共享内存映射向量
【发布时间】:2018-10-10 11:25:04
【问题描述】:

如何将字符串附加到地图中包含的矢量?结构是 map(float,vector(string)),其中映射位于共享内存中。我的问题是如果 key==desired key 然后将字符串附加到字符串向量?

【问题讨论】:

标签: c++ boost shared-memory


【解决方案1】:

你的意思是这样的:

#include <map>
#include <vector>
#include <string>
#include <iostream>

int main()
{
        std::map<float, std::vector<std::string>> m;

        m[.5f].emplace_back("First");
        m[.5f].emplace_back("Second");
        m[.0f].emplace_back("Hello");
        m[.0f].emplace_back("World");

        for(const auto& [key, value] : m)
        {
                std::cout << "Key: " << key << '\n';
                for(const auto& str : value)
                        std::cout << '\t' << str << '\n';
        }
        std::cout.flush();
        return 0;
}

【讨论】:

  • 我已经在一个进程中使用托管共享内存初始化并分配了映射对象。我需要在另一个进程中添加更多元素。需要扩展地图或矢量。
  • @Max 这非常简单。如果没有高级机制(范围分配器),这些都不能转化为共享内存容器,即使这样,它也绕过了构造参数转发机制的边缘。我会发布一个答案只是为了显示。
  • Posted。如果你准备好迎接挑战,你可以尝试以自然的方式只写doesn't exist 分支(比如_map.emplace(f, {s});,因为你通常会写)。当然,我的解决方案通过使用默认构造 operator[] 来作弊。
【解决方案2】:

实际上,在共享内存中执行此操作非常困难。

如果所有分配器都正确,并添加锁定,通常会得到非常笨重的代码,由于所有分配器都在传递而难以阅读。

但是,您可以使用 Boost 的作用域分配器适配器,它会做很多(很多)魔法,让生活更美好。

我认为下面的代码示例几乎可以确定最佳位置。

警告:这是建立在多年试图击败它以使其屈服的经验之上的。如果您刚好超出“魔术”的边界(主要是由于uses_allocator&lt;&gt;scoped_allocator_adaptor 而提供的就地构造支持),您会发现它会崩溃并且您将编写大量手动构造函数/转换调用让它发挥作用。

Live On Coliru

#define DEMO
#include <iostream>
#include <iomanip>
#include <mutex>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp> // For Coliru (doesn't support shared memory)
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/container/scoped_allocator.hpp>

namespace bip = boost::interprocess;
namespace bc = boost::container;

namespace Shared {
    using Segment = bip::managed_mapped_file; // Coliru doesn't support bip::managed_shared_memory

    template <typename T> using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Segment::segment_manager> >;
    template <typename V>
        using Vector = bip::vector<V, Alloc<V> >;
    template <typename K, typename V, typename Cmp = std::less<K> >
        using Map = bip::map<K, V, Cmp, Alloc<std::pair<K const, V> > >;

    using String = bip::basic_string<char, std::char_traits<char>, Alloc<char> >;

    using Mutex = bip::interprocess_mutex;
}

namespace Lib {
    using namespace Shared;
    struct Data {
        using Map = Shared::Map<float, Shared::Vector<Shared::String> >;

        mutable Mutex _mx;
        Map _map;

        template <typename Alloc> Data(Alloc alloc = {}) : _map(alloc) {}

        bool append(float f, std::string s) {
            std::lock_guard<Mutex> lk(_mx); // lock

            auto it = _map.find(f);
            bool const exists = it != _map.end();

#ifndef DEMO
            if (exists) {
                it->second.emplace_back(s);
            }
#else
            // you didn't specify this, but lets insert new keys here, if
            // only for the demo
            _map[f].emplace_back(s);
#endif
            return exists;
        }

        size_t size() const {
            std::lock_guard<Mutex> lk(_mx); // lock
            return _map.size();
        }

        friend std::ostream& operator<<(std::ostream& os, Data const& data) {
            std::lock_guard<Mutex> lk(data._mx); // lock

            for (auto& [f,v] : data._map) {
                os << f << " ->";
                for (auto& ss : v) {
                    os << " " << std::quoted(std::string(ss));
                }
                os << "\n";
            }

            return os;
        }
    };
}

struct Program {
    Shared::Segment msm { bip::open_or_create, "data.bin", 10*1024 };
    Lib::Data& _data = *msm.find_or_construct<Lib::Data>("data")(msm.get_segment_manager());

    void report() const {
        std::cout << "Map contains " << _data.size() << " entries\n" << _data;
    }
};

struct Client : Program {
    void run(float f) {
        _data.append(f, "one");
        _data.append(f, "two");
    }
};

int main() {
    {
        Program server;
        server.report();

        Client().run(.5f);
        Client().run(.6f);
    }

    // report again
    Program().report();
}

第一次运行将打印:

Map contains 0 entries
Map contains 2 entries
0.5 -> "one" "two"
0.6 -> "one" "two"

第二次运行:

Map contains 2 entries
0.5 -> "one" "two"
0.6 -> "one" "two"
Map contains 2 entries
0.5 -> "one" "two" "one" "two"
0.6 -> "one" "two" "one" "two"

【讨论】:

    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 2023-04-06
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    相关资源
    最近更新 更多