我尝试使用boost :: interprocess以在进程之间共享数据,并利用shared_ptr进行生命周期管理。我有一张驻留在共享内存中的地图,两个进程应该访问它。
boost::shared_ptr<boost::interprocess::managed_mapped_file> segment =
boost::make_shared<boost::interprocess::managed_mapped_file>
(boost::interprocess::open_or_create,
"./some-mmap.txt", //file name
65536); //segment size in bytes
pair_allocator_type alloc_inst(segment->get_segment_manager());
elements = boost::interprocess::make_managed_shared_ptr(
segment->find_or_construct<map_type>("elements")
(std::less<IdType>(), alloc_inst),
*segment
);
在我有一个测试程序中,父和子进程基本上都使用上面的代码。因此,它们使用相同的底层文件,共享对象的相同名称(&#34;元素&#34;),相同的类型等。
但是,我注意到只要子进程死掉,集合的大小就会降到0.奇怪。我进行了调查,似乎它与elements
的破坏有关(当这个共享指针超出范围时)。每当elements
超出范围时,底层集合的大小就会变为0。
我还看到elements
在父级和子级进程中都有use_count
正好1 。对于有意义的家长,但我不知道为什么孩子会这样。我的假设是,当Child进程终止时,use_count将降为0,然后清除集合。
我想要的是,当Child进程终止时,不会销毁指向的对象(map)。我不应该假设哪些流程是活跃的,哪些不是。
boost::interprocess::shared_ptr
? 编辑 - 有关收集的说明
elements
是boost::interprocess::map
,它将某个IdType
映射到共享内存共享指针ShmemType
。当Child进程终止时,elements
的大小会降为0。
typedef boost::interprocess::managed_mapped_file::segment_manager segment_manager_type;
typedef std::pair<const IdType, ShmemType::pointer_type> pair_type;
typedef boost::interprocess::allocator<pair_type, segment_manager_type> pair_allocator_type;
typedef boost::interprocess::map<IdType, ShmemType::pointer_type, std::less<IdType>, pair_allocator_type> map_type;
编辑 - 来自提升文档的示例
我从增强文档中提取了示例并对其进行了扩展,以找出原始问题的根本原因。
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <string>
#include <cstdlib> //std::system
using namespace boost::interprocess;
typedef allocator<int, managed_mapped_file::segment_manager> ShmemAllocator;
typedef vector<int, ShmemAllocator> MyVector;
#include <iostream>
//Main function. For parent process argc == 1, for child process argc == 2
int main(int argc, char *argv[])
{
if(argc == 1){ //Parent process
//Create a new segment with given name and size
managed_mapped_file segment(open_or_create, "./a_MySharedMemory.txt", 65536);
//Initialize shared memory STL-compatible allocator
const ShmemAllocator alloc_inst (segment.get_segment_manager());
// MyVector* elements = segment.find_or_construct<MyVector>("some-vector") //object name
// (alloc_inst);
typedef boost::interprocess::managed_shared_ptr<MyVector, boost::interprocess::managed_mapped_file>::type map_pointer_type;
map_pointer_type elements = boost::interprocess::make_managed_shared_ptr(
segment.find_or_construct<MyVector>("some-vector") //object name
(alloc_inst),
segment
);
for(int i = 0; i < 100; ++i) //Insert data in the vector
elements->push_back(i);
std::cout << elements->size() << std::endl;
std::cout << elements->at(0) << std::endl;
std::cout << elements->at(30) << std::endl;
//Launch child process
std::string s(argv[0]); s += " child ";
if(0 != std::system(s.c_str()))
return 1;
std::cout << elements->size() << std::endl;
std::cout << elements->at(0) << std::endl;
std::cout << elements->at(30) << std::endl;
}
else{ //Child process
//Open the managed segment
managed_mapped_file segment(open_only, "./a_MySharedMemory.txt");
const ShmemAllocator alloc_inst (segment.get_segment_manager());
typedef boost::interprocess::managed_shared_ptr<MyVector, boost::interprocess::managed_mapped_file>::type map_pointer_type;
map_pointer_type elements = boost::interprocess::make_managed_shared_ptr(
segment.find_or_construct<MyVector>("some-vector") //object name
(alloc_inst),
segment
);
// MyVector* elements = segment.find_or_construct<MyVector>("some-vector") //object name
// (alloc_inst);
//Use vector in reverse order
std::sort(elements->rbegin(), elements->rend());
}
return 0;
}
在这种情况下,在子进程终止后,父进程中的向量大小为== 0。如果我使用原始指针(MyVector* elements = segment.find_or_construct...
),那么可以在父进程中按预期使用该集合。
所以我仍然怀疑共享指针的行为
答案 0 :(得分:2)
boost::interprocess::shared_ptr
? 你做得对。但是,您不需要共享指针中的段。只需确保该段超过任何进程间shared_ptrs(或者,对于共享内存段的任何引用)。
没有
shared_ptr
的{{1}} 返回使用默认分配器和删除器构建的共享指针的实例,该指针是已在传递的托管段中分配的类型为T的指针。
other page明确提及(强调我的):
由于必须在托管段中创建引用计数和shared_ptr所需的其他辅助数据,并且删除器必须从段中删除该对象,因此用户必须指定分配器对象和构造shared_ptr
的非空实例时的删除对象
答案 1 :(得分:2)
我设法解决了这个问题。问题与共享指针的制作方式有关
如果您调用boost::interprocess::make_managed_shared_ptr
N次以创建共享内存中对象的共享指针,则会获得与共享内存中相同对象的本质上不同(完全不相关)的共享指针。我在Parent和Child进程中这样做,然后当Child进程死亡时,use count变为0并擦除了指向的对象(地图)。
解决方案是显式创建一个命名的共享指针。
typedef boost::interprocess::allocator<void, segment_manager_type> void_allocator_type;
typedef boost::interprocess::deleter<map_type, segment_manager_type> map_deleter_type;
typedef boost::interprocess::shared_ptr<map_type, void_allocator_type, map_deleter_type> map_pointer_type;
segment_manager_type* segment_manager = segment->get_segment_manager();
pair_allocator_type alloc_inst(segment_manager);
segment->construct<map_pointer_type>("elements ptr")(
segment->construct<map_type>("elements")(std::less<IdClass>(), alloc_inst), //object to own
void_allocator_type(segment_manager), //allocator
map_deleter_type(segment_manager) //deleter
);
然后在Child进程中只获取此指针的副本
map_pointer_type elements = *segment->find<map_pointer_type>("elements ptr").first;
答案 2 :(得分:0)
我现在看到,如果我尝试在Child进程死后在共享内存中的父进程中创建任何对象,我会收到一个断言错误:
assertion "hdr->m_value_alignment == algn" failed:
file "/usr/include/boost/interprocess/detail/segment_manager_helper.hpp", line 181,
function: static boost::interprocess::detail::block_header* boost::interprocess::detail::block_header::block_header_from_value(const void*, size_t, size_t)
所以现在我怀疑这是我从父进程中生成子进程的方式。
//Launch child process
std::string s(argv[0]); s += " child";
std::cout << "Child about to be born" << std::endl;
if(0 != std::system(s.c_str())){
std::cout << "(Parent): Child failed!" << std::endl;
return 1;
}