![]() |
Home | Libraries | People | FAQ | More |
As mentioned, container developers might need to change their implementation to make them compatible with Boost.Interprocess, because implementation usually ignore allocators with smart pointers. Hopefully several Boost containers are compatible with Interprocess.
Boost.Unordered containers are compatible
with Interprocess, so programmers can store hash containers in shared memory
and memory mapped files. Here is a small example storing unordered_map
in shared memory:
#include <boost/interprocess/managed_shared_memory.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/unordered_map.hpp> //boost::unordered_map #include <functional> //std::equal_to #include <boost/container_hash/hash.hpp> //boost::hash int main () { using namespace boost::interprocess; //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MyName"); } ~shm_remove(){ shared_memory_object::remove("MyName"); } } remover; //Create shared memory managed_shared_memory segment(create_only, "MyName", 65536); //Note that unordered_map<Key, MappedType>'s value_type is std::pair<const Key, MappedType>, //so the allocator must allocate that pair. typedef int KeyType; typedef float MappedType; typedef std::pair<const int, float> ValueType; //Typedef the allocator typedef allocator<ValueType, managed_shared_memory::segment_manager> ShmemAllocator; //Alias an unordered_map of ints that uses the previous STL-like allocator. typedef boost::unordered_map < KeyType , MappedType , boost::hash<KeyType> ,std::equal_to<KeyType> , ShmemAllocator> MyHashMap; //Construct a shared memory hash map. //Note that the first parameter is the initial bucket count and //after that, the hash function, the equality function and the allocator MyHashMap *myhashmap = segment.construct<MyHashMap>("MyHashMap") //object name ( 3u, boost::hash<int>(), std::equal_to<int>() // , segment.get_allocator<ValueType>()); //allocator instance //Insert data in the hash map for(std::size_t i = 0; i < 100u; ++i){ myhashmap->insert(ValueType((int)i, (float)i)); } return 0; }
The widely used Boost.MultiIndex library is compatible with Boost.Interprocess so we can construct pretty good databases in shared memory. Constructing databases in shared memory is a bit tougher than in normal memory, usually because those databases contain strings and those strings need to be placed in shared memory. Shared memory strings require an allocator in their constructors so this usually makes object insertion a bit more complicated.
Here is an example that shows how to put a multi index container in shared memory. Note also how MultiIndex supports the uses-allocator construction so that allocator arguments can be automatically propagated into internal allocator-aware components:
#include <boost/interprocess/managed_shared_memory.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/container/string.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> using namespace boost::interprocess; namespace bmi = boost::multi_index; typedef managed_shared_memory::allocator<char>::type char_allocator; typedef boost::container::basic_string<char, std::char_traits<char>, char_allocator>shm_string; //Data to insert in shared memory struct employee { typedef char_allocator allocator_type; //enables uses-allocator protocol int id; int age; shm_string name; employee( int id_ , int age_ , const char *name_ , const char_allocator &a) : id(id_), age(age_), name(name_, a) {} }; //Tags struct id{}; struct age{}; struct name{}; // Define a multi_index_container of employees with following indices: // - a unique index sorted by employee::int, // - a non-unique index sorted by employee::name, // - a non-unique index sorted by employee::age. typedef bmi::multi_index_container< employee, bmi::indexed_by< bmi::ordered_unique <bmi::tag<id>, bmi::member<employee,int,&employee::id> >, bmi::ordered_non_unique< bmi::tag<name>, bmi::member<employee,shm_string,&employee::name> >, bmi::ordered_non_unique <bmi::tag<age>, bmi::member<employee,int,&employee::age> > >, managed_shared_memory::allocator<employee>::type > employee_set; int main () { //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MyName"); } ~shm_remove(){ shared_memory_object::remove("MyName"); } } remover; //Create shared memory managed_shared_memory segment(create_only,"MyName", 65536); //Construct the multi_index in shared memory (classic construction) employee_set *es = segment.construct<employee_set> ("My MultiIndex Container") //Container's name in shared memory ( employee_set::ctor_args_list() , segment.get_allocator<employee>()); //Ctor parameters //Now insert elements char_allocator ca(segment.get_allocator<char>()); es->insert(employee(0,31, "Joe", ca)); es->insert(employee(1,27, "Robert", ca)); es->insert(employee(2,40, "John", ca)); segment.destroy_ptr(es); //Now re-construct it using the uses-allocator protocol es = segment.construct<employee_set> ("My MultiIndex Container") //Container's name in shared memory ( employee_set::ctor_args_list() ); //Allocator parameters is implicit //Now emplace elements (more natural, the allocator is implicitly propagated) es->emplace(0,31, "Joe"); es->emplace(1,27, "Robert"); es->emplace(2,40, "John"); segment.destroy_ptr(es); return 0; }
Programmers can place Boost.CircularBuffer
containers in shared memory provided they disable debugging facilities with
defines BOOST_CB_DISABLE_DEBUG
or the more general NDEBUG.
The reason is that those debugging facilities are only compatible with raw
pointers.