c++ - boost 的进程间段管理器分配器本身可以与其他进程共享吗?

标签 c++ boost shared-memory interprocess

我正在使用 boost::interprocess 创建共享的进程间映射。 为此,我从映射所在的共享内存段的 segment_manager 创建了一个分配器。

映射的元素值类型是 basic_string,它本身被模板化以使用从同一段管理器创建的 char 分配器。 在一个过程中,我创建 map ,在另一个过程中,我在该过程中使用 map 迭代器搜索项目,在某些情况下,我使用迭代器调用 map::erase。

这会导致访问冲突异常,我知道我正在使用有效的迭代器进行调用。 访问冲突发生在对 basic_string 的析构函数的调用中,该 basic_string 是迭代器指向的“对”中的“第二个”。 当我在插入后立即在写入过程中使用迭代器执行相同的删除操作时,没有访问冲突。

看起来好像读取进程正在尝试使用元素的分配器释放元素的内存,该分配器是在写入进程中创建的,而该分配器仅在创建它的进程中有效。

这是否意味着分配器本身不能共享?

我希望分配器在两个进程中都可用,因为它的状态应该只包含在两个进程中都有效的相对指针。 如果不是,我如何在进程之间共享使用共享内存(堆)分配的元素? 在将它们传递给 basic_string 元素之前,我是否应该在编写过程中以特殊方式创建这些分配器,以允许我在另一个进程的删除操作中使用它们?

还有什么可能导致访问冲突?

最佳答案

分配器很好(魔法在 offset_ptr 中,它跨进程边界是透明的)。

如果“客户端”破坏了字符串,那么您正在做的不是阅读。您很可能会收到一份拷贝,例如:

auto by_copy = smap.find(key)->second; // makes a copy

尝试,例如做

auto const& by_ref = smap.find(key)->second; // doesn't copy

或者,您可能正在执行 smap[key],如果 key 不存在,它会自动分配。这可能会导致老式的竞争条件(在进程之间共享数据很像在线程之间共享数据:您需要适当的同步)。

最后,您没有提及关于键的/anything/,但如果它也是一个字符串,那么只有键查找很容易从共享内存中分配(而且,它是临时的,它会破坏)。竞争条件再次出现。另见 want to efficiently overcome mismatch between key types in a map in Boost.Interprocess shared memory

演示

在没有适当的 SSCCE 的情况下或 MCVE ,让我向你扔一个。您可能会发现自己的做法有所不同。

#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/map.hpp>

namespace bip = boost::interprocess;

namespace shared {
    namespace bc  = boost::container;

    using Segment = bip::managed_shared_memory;
    using Manager = Segment::segment_manager;
    template <typename T>
    using Alloc   = bc::scoped_allocator_adaptor<bip::allocator<T, Manager> >;

    using String  = bip::basic_string<char, std::char_traits<char>, Alloc<char> >;
    template <typename K, typename V, typename Cmp = std::less<K> >
        using Map = bip::map<K, V, Cmp, Alloc<std::pair<K const, V> > >;
};

int main() {
    using namespace shared;

    Segment smt(bip::open_or_create, "de06c60a-0b80-4b20-a805-b3f405f35427", 20ul<<20); // 20 mb
    auto& mat = *smt.find_or_construct<Map<String, String> >("dict")(smt.get_segment_manager());

    if (mat.empty()) {
        mat.emplace("1", "one");
        mat.emplace("2", "two");
        mat.emplace("3", "three");
    } else {
        // shared string factory
        auto ss = [&](auto... stuff) { return String(stuff..., smt.get_segment_manager()); };

        auto  copy = mat.at(ss("3")); // constructs and destructs temp String("3"); constructs copy
        auto& ref  = mat.at(ss("2")); // constructs and destructs temp String("2"); no copy
        std::cout << "copy: " << copy << "\n";
        std::cout << "ref: "  << ref  << "\n";

        // iterate with no shared temps or copies:
        for (auto& p : mat)
            std::cout << "entry '" << p.first << "' -> '" << p.second << "'\n";
    } // destructs copy
}

在 Coliru 上也是如此,但使用内存映射文件(因为那里不允许共享内存):

Live On Coliru

using Segment = bip::managed_mapped_file;

第一次运行时不打印任何内容,后续运行:

copy: three
ref: two
entry '1' -> 'one'
entry '2' -> 'two'
entry '3' -> 'three'

关于c++ - boost 的进程间段管理器分配器本身可以与其他进程共享吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44982935/

相关文章:

c++ - boost program_options 生成一个 Klocwork MLK.MUST

boost - const shared_ptr到shared_ptr

python - 多处理中的共享内存

azure - 如何修复 MPI_ERR_RMA_SHARED?

c++ - 编译字符串并将其作为 vector 返回

c++ - 无法在 C++ 中使用 LVM_GETITEMTEXT 而不导致目标应用程序崩溃

C++ 在多个子字符串上拆分字符串

c++ - 尝试使用 CreateFileMapping 和自定义 DACL 创建只读共享内存区域在 OpenFileMapping 中失败

c++ - #include 和可能的循环引用

c++ - 我在 main 下的输出不是我所期望的