我正在使用 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 上也是如此,但使用内存映射文件(因为那里不允许共享内存):
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/