我正在跟踪这个Boost::进程间指南。我有一个以std::string
为成员的结构,我用std::string
作为键值创建了这个结构的multimap。我可以用生产者代码从结构中访问std::string
。但是,当我试图访问消费者代码中的同一个std::string
成员时,我就得到了核心转储。
有人能帮我吗。提前谢谢。我给出的代码如下:
生产者代码:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
struct temp
{
int x;
int y;
std::string name;
};
int main ()
{
using namespace boost::interprocess;
try
{
shared_memory_object::remove("MySharedMultimap");
managed_shared_memory segment
(create_only
,"MySharedMultimap" //segment name
,65536); //segment size in bytes
typedef std::string KeyType;
typedef struct temp MappedType;
typedef std::pair<const std::string, struct temp> ValueType;
typedef allocator< ValueType, managed_shared_memory::segment_manager>
ShmemAllocator;
typedef multimap<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MyMultimap;
//Initialize shared memory STL-compatible allocator
const ShmemAllocator alloc_inst (segment.get_segment_manager());
//Construct a shared memory
MyMultimap *mymultimap =
segment.construct<MyMultimap>("MyMultimap") //object name
(alloc_inst);//first ctor parameter
std::string s = "key1";
mymultimap->insert(std::pair<KeyType, MappedType>(s, t1));
}
catch(...)
{
shared_memory_object::remove("MySharedMultimap");
throw;
}
}
消费者代码:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
struct temp
{
int x;
int y;
std::string name;
};
int main ()
{
using namespace boost::interprocess;
try
{
managed_shared_memory segment
(open_only
,"MySharedMultimap"); //segment name
typedef std::string KeyType;
typedef struct temp MappedType;
typedef std::pair<const std::string, struct temp> ValueType;
//Alias an STL compatible allocator of ints that allocates ints from the managed
//shared memory segment. This allocator will allow to place containers
//in managed shared memory segments
typedef allocator<ValueType , managed_shared_memory::segment_manager>
ShmemAllocator;
//Alias a vector that uses the previous STL-like allocator
typedef multimap< KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MyMultimap;
//Find the vector using the c-string name
MyMultimap *mymultimap = segment.find<MyMultimap>("MyMultimap").first;
std:: cout << " multimap size size : " << mymultimap->size() << std::endl;
for(auto i = mymultimap->begin(); i != mymultimap->end(); ++i)
{
std::cout << i->first << std::endl; // core dump ( as we are accessing std::string )
std::cout << i->second.x << std::endl; // works fine
std::cout << i->second.name << std::endl; // core dump ( as we are accessing std::string )
}
}
catch(...){
shared_memory_object::remove("MySharedMultimap");
throw;
}
}
发布于 2022-10-12 11:39:32
您需要使用共享内存分配器。你已经有了,为什么不使用它们呢?
首先,我将您的测试程序简化并组合成一个:住在Coliru。Note,这仍然存在同样的问题。
解决问题
您需要使用带有共享内存分配器的字符串:
namespace bip = boost::interprocess;
using Segment = bip::managed_shared_memory;
using Mgr = Segment::segment_manager;
template <typename T>
using Alloc = bip::allocator<T, Mgr>;
using String = bip::basic_string<char, std::char_traits<char>, Alloc<char>>;
现在,用它:
struct temp {
int x;
int y;
String name;
};
using MyMultimap = Multimap<String, temp>;
这意味着您还必须转换"more data"
:
// assume sa = String::allocator_type sa(segment.get_segment_manager())
String more_data("more data", sa);
m.insert({String("key", sa), temp{1, 2, more_data}});
工作,住在Coliru,打印:
multimap size size : 1
key
1
more data
解决那些烦人的分配器?
那是很多手动分配器的杂耍。使用作用域分配器可以减少这样的情况:
template <typename T>
using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;
现在你可以写:
m.emplace("key", temp{1, 2, String("more data", sa)});
要将分配器传播到
temp::name
成员,需要使temp
分配器具有感知性。multimap
不是一个适合用它来展示这一点的例子,因为它的接口并没有真正地使用它。 为了完整起见,以下是它的外观草图: struct {使用String = Shared::String;使用allocator_type = String::allocator_type;temp(temp &)=默认;temp (temp&)=String::allocator_type;temp(temp const& rhs,allocator_type a):x(rhs.x),y(rhs.y),name(rhs.name.data(),rhs.name.size(),a) {} temp(temp& rhs,allocator_type a):temp(std::move(rhs)) { if (a = name.get_allocator()) name = String(name.data(),name.size(),a;}模板temp(int x,int y,char const* name,Alloc a= {}):x(x),y(y),name(name,a) {} int x;int y;String name;};
异构查找
比你的问题早一步:你可能会想要m.find("key")
,或者.lower_bound
,.upper_bound
和.equal_range
。为了避免相同的分配器混乱和低效率地分配临时人员,如下所示:
String::allocator_type sa(m.get_segment_manager());
auto r = m.equal_range(String("key", sa));
使用透明的比较:
using MyMultimap = Multimap<String, temp, std::less<>>;
现在你可以“只是”写:
// key lookup:
for (auto& [k, v] : boost::make_iterator_range(m.equal_range("key"))) {
std::cout << k << "\n";
std::cout << v.x << "\n";
std::cout << v.name << "\n";
}
全演示
#include <boost/container/map.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/string.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
namespace bip = boost::interprocess;
namespace Shared {
namespace bc = boost::container;
#ifndef COLIRU
using Segment = bip::managed_shared_memory;
#else
using Segment = bip::managed_mapped_file;
#endif
using Mgr = Segment::segment_manager;
template <typename T>
using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>;
template <typename K, typename V, typename Cmp = std::less<K>>
using Multimap = bc::multimap<K, V, Cmp, Alloc<std::pair<K const, V>>>;
using String = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
static auto Remove = bip::shared_memory_object::remove;
} // namespace Shared
struct temp {
using String = Shared::String;
using allocator_type = String::allocator_type;
temp(temp const&) = default;
temp(temp&&) = default;
temp(temp const& rhs, allocator_type a)
: x(rhs.x)
, y(rhs.y)
, name(rhs.name.data(), rhs.name.size(), a) {}
temp(temp&& rhs, allocator_type a) : temp(std::move(rhs)) {
if (a != name.get_allocator())
name = String(name.data(), name.size(), a);
}
template <typename Alloc>
temp(int x, int y, char const* name, Alloc a = {})
: x(x)
, y(y)
, name(name, a) {}
int x;
int y;
String name;
};
int main(int argc, char** /*unused*/) {
using namespace Shared;
using MyMultimap = Multimap<String, temp, std::less<>>;
auto constexpr shm_name = "MySharedMemory";
auto constexpr map_name = "MyMultimap";
try {
if (argc > 1) { // Producer
Remove(shm_name);
Segment segment(bip::create_only, shm_name, 65536);
auto* sm = segment.get_segment_manager();
auto& m = *segment.construct<MyMultimap>(map_name) // object name
(sm); // first ctor parameter
temp&& v{1, 2, "more data", sm};
m.emplace("key", v);
} else { // Consumer
Segment segment(bip::open_only, shm_name);
auto& m = *segment.find<MyMultimap>(map_name).first;
std::cout << " multimap size size : " << m.size() << "\n";
// key lookup:
for (auto& [k, v] : boost::make_iterator_range(m.equal_range("key"))) {
std::cout << k << "\n";
std::cout << v.x << "\n";
std::cout << v.name << "\n";
}
}
} catch (...) {
// remove(name);
throw;
}
}
与G.
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -lrt -DCOLIRU
./a.out producer
./a.out
打印
multimap size size : 1
key
1
more data
https://stackoverflow.com/questions/74038390
复制相似问题