I'm trying to use the boost::interprocess in order to share data between processes and utilize the shared_ptr for lifecycle management. I have a map residing in the shared memory and two processes should access it.
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
);
In a test program I have, a Parent and a Child process which essentially both use the piece of code from above. Therefore, they use the same underlying file, same name of the shared object ("elements"), same types, etc.
However, I noticed that whenever a child process dies, the size of the collection dropped to 0. Strange. I investigated and it seemed that it had to do with the destruction of elements
(when this shared pointer goes out of scope). Whenever elements
went out of scope, the size of the underlying collection went to 0.
I also saw that the elements
has the use_count
exactly 1 in both Parent and Child process. For Parent that makes sense, but I don't get it why is it the case for Child. My assumption is that when the Child process dies, the use_count drops to 0, and then the collection is cleared.
What I want is that the pointed object (map) is not destroyed when the Child process dies. I should not make assumptions which processes are active and which ones not.
- Am I initializing the
boost::interprocess::shared_ptr
in a wrong way? - Am I missing completely the semantics of this pointer --> is it used only to manage shared-memory objects lifecycle only within one process and not across processes?
- How to have a shared_ptr whose use_count is shared across processes?
EDIT - clarifications on collection
The elements
is a boost::interprocess::map
that maps a certain IdType
to a shared-memory shared pointer to ShmemType
. The size of elements
drops to 0 when the Child process dies.
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;
EDIT - example from boost docs
I've taken the examples from boost docs and expanded on it to track down the root cause of my original problem.
#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;
}
In this case the vector has size == 0 in the parent process after the child process dies. If I use the raw pointer (MyVector* elements = segment.find_or_construct...
), then the collection can be used as expected in the parent process.
So I still have my doubts about the behavior of the shared pointer