[interprocess] shared map of string to string?
I'm using boost.interprocess to build a map from string to string that can be shared between multiple processes, with all read/write access protected by a mutex. I'm having a hard time making it work. Here's a cut-down version of the declaration: template < typename KeyType, typename ValueType, typename StoredKeyType = KeyType, typename StoredValueType = ValueType > class SharedMap : private boost::noncopyable { public: SharedMap( const std::string & shmName, const std::size_t shmSize, const std::size_t initBucketCount = 10 ); ~SharedMap(); void setOneValue( const KeyType & key, const ValueType & value ); bool getOneValue( const KeyType & key, ValueType & value ); void clear(); private: typedef std::pair< const StoredKeyType, StoredValueType > StoredPairType; typedef boost::interprocess::managed_shared_memory ShmManagerType; typedef boost::interprocess::allocator< StoredPairType, ShmManagerType::segment_manager > ShmAllocatorType; typedef boost::interprocess::interprocess_mutex ShmMutexType; typedef boost::interprocess::scoped_lock< ShmMutexType > ShmScopedLock; typedef boost::unordered_map< StoredKeyType, StoredValueType, boost::hash< StoredKeyType >, std::equal_to< StoredKeyType >, ShmAllocatorType > ShmMapType; std::string m_sShmName; ShmManagerType m_manager; ShmMutexType * m_pMutex; ShmMapType * m_pMap; }; // end class SharedMap typedef SharedMap< /* KeyType = */ std::string, /* ValueType = */ std::string, /* StoredKeyType = */ boost::interprocess::string, /* StoredValueType = */ boost::interprocess::string > SharedStringMap; And some important bits of the implementation: #define SHARED_MAP( ret_type ) \ template < \ typename KeyType, \ typename ValueType, \ typename StoredKeyType, \ typename StoredValueType \ > \ ret_type \ SharedMap< \ KeyType, \ ValueType, \ StoredKeyType, \ StoredValueType \ > SHARED_MAP()::SharedMap( const std::string & shmName, const std::size_t shmSize, const std::size_t initBucketCount /* = 10 */ ) : m_sShmName( shmName ), m_manager( boost::interprocess::open_or_create, shmName.c_str(), shmSize ), m_pMutex( m_manager.find_or_construct< ShmMutexType >( "mutex" )() ), m_pMap( m_manager.find_or_construct< ShmMapType >( "map" )( initBucketCount, boost::hash< StoredKeyType >(), std::equal_to< StoredKeyType >(), m_manager.get_allocator< StoredPairType >() ) ) { } SHARED_MAP()::~SharedMap() { try { m_pMutex->unlock(); } catch ( ... ) { } } SHARED_MAP( void )::clear() { ShmScopedLock lock( *m_pMutex ); m_pMap->clear(); } It works fine the first time I run the program, but on the second attempt I get a SIGSEGV when I try to clear the map. My test loop is basically: create or find map for each rep clear map insert values done GDB tells me that this error is originating here: Program received signal SIGSEGV, Segmentation fault. __libc_free (mem=0x8143a48) at malloc.c:3709 3709 if (chunk_is_mmapped(p)) /* release mmapped memory. */ (gdb) bt #0 __libc_free (mem=0x8143a48) at malloc.c:3709 #1 0x001efd12 in operator delete (ptr=<value optimized out>) at ../../../../libstdc++-v3/libsupc++/del_op.cc:44 #2 0x08053d49 in __gnu_cxx::new_allocator<char>::deallocate (this=0xb7fa4334, __p=0x8143a48 <Address 0x8143a48 out of bounds>) at /usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/ext/new_allocator.h:95 #3 0x0805e677 in boost::interprocess_container::containers_detail::basic_string_base<std::allocator<char> >::deallocate (this=0xb7fa4334, p=0x8143a48 <Address 0x8143a48 out of bounds>, n=24) at /usr/include/boost/interprocess/containers/container/string.hpp:309 #4 0x0805dac2 in boost::interprocess_container::containers_detail::basic_string_base<std::allocator<char> >::deallocate_block (this=0xb7fa4334) at /usr/include/boost/interprocess/containers/container/string.hpp:341 #5 0x0805d167 in boost::interprocess_container::containers_detail::basic_string_base<std::allocator<char> >::~basic_string_base (this=0xb7fa4334, __in_chrg=<value optimized out>) at /usr/include/boost/interprocess/containers/container/string.hpp:119 #6 0x0805bfe7 in {b::ic::string}::~basic_string (this=0xb7fa4334, __in_chrg=<value optimized out>) at /usr/include/boost/interprocess/containers/container/string.hpp:617 #7 0x0805d671 in std::pair<{b::ic::string} const, {b::ic::string} >::~pair (this=0xb7fa4334, __in_chrg=<value optimized out>) at /usr/lib/gcc/i686-redhat-linux/4.4.2/../../../../include/c++/4.4.2/bits/stl_pair.h:68 #8 0x08063636 in boost::unordered_detail::destroy<std::pair<{b::ic::string} const, {b::ic::string} > > (x=0xb7fa4334) at /usr/include/boost/unordered/detail/hash_table.hpp:233 #9 0x08062d55 in boost::unordered_detail::hash_table_data_unique_keys<ip::allocator<std::pair<{b::ic::string} const, {b::ic::string} >, ip::segment_manager<char, ip::rbtree_best_fit<ip::mutex_family, ip::offset_ptr<void>, 0u>, ip::iset_index> > >::allocators::destroy (this=0xb7f9f0d4, ptr=...) at /usr/include/boost/unordered/detail/hash_table_impl.hpp:133 #10 0x080619fc in boost::unordered_detail::hash_table_data_unique_keys<ip::allocator<std::pair<{b::ic::string} const, {b::ic::string} >, ip::segment_manager<char, ip::rbtree_best_fit<ip::mutex_family, ip::offset_ptr<void>, 0u>, ip::iset_index> > >::delete_to_bucket_end (this=0xb7f9f0d4, begin=...) at /usr/include/boost/unordered/detail/hash_table_impl.hpp:832 #11 0x0805fc63 in boost::unordered_detail::hash_table_data_unique_keys<ip::allocator<std::pair<{b::ic::string} const, {b::ic::string} >, ip::segment_manager<char, ip::rbtree_best_fit<ip::mutex_family, ip::offset_ptr<void>, 0u>, ip::iset_index> > >::clear_bucket ( this=0xb7f9f0d4, b=...) at /usr/include/boost/unordered/detail/hash_table_impl.hpp:867 #12 0x0805e2ff in boost::unordered_detail::hash_table_data_unique_keys<ip::allocator<std::pair<{b::ic::string} const, {b::ic::string} >, ip::segment_manager<char, ip::rbtree_best_fit<ip::mutex_family, ip::offset_ptr<void>, 0u>, ip::iset_index> > >::clear ( this=0xb7f9f0d4) at /usr/include/boost/unordered/detail/hash_table_impl.hpp:879 #13 0x0805d918 in boost::unordered_map<{b::ic::string}, {b::ic::string}, boost::hash<{b::ic::string} >, std::equal_to<{b::ic::string} >, ip::allocator<std::pair<{b::ic::string} const, {b::ic::string} >, ip::segment_manager<char, ip::rbtree_best_fit<ip::mutex_family, ip::offset_ptr<void>, 0u>, ip::iset_index> > >::clear (this=0xb7f9f0c4) at /usr/include/boost/unordered/unordered_map.hpp:271 #14 0x0805cdc3 in Tony::SharedMap<{std::string}, {std::string}, {b::ic::string}, {b::ic::string} >::clear (this=0xbffff40c) at SharedMap.cpp:203 #15 0x0804e3e4 in main (argc=1, argv=0xbffff744) at SharedMapTest.cpp:99 I've done the following substitutions: std::basic_string<char, std::char_traits<char>, std::allocator<char> > -> {std::string} boost::interprocess_container::basic_string<char, std::char_traits<char>, std::allocator<char> > -> {b::ic::string} ip:: -> ip:: Interestingly, it looks like the mutex survives program stops and starts just fine: if I try to run my test case a third time, it sits and waits on the mutex (which got locked just before the 'clear' crashed out in the 2nd invocation) Platform is GCC 4.4.2 (fedora rpm 4.4.2-20) with the RPM packages of boost (1.39.0-8). Any hints would be very much appreciated. I can get a full working test case up on the web, but I need to pull out some bits (especially from the test routine) that rely on other parts of my project. Alternately, if anyone knows of a freely-available implementation of this functionality (or, even better, one that stores std::strings directly instead of having to go to/from b::ip::strings, and maybe one that auto-sizes its shared memory pool)... I'd *definitely* like to hear about that. :) Thanks in advance! Regards, Tony
On Jan 19, 2010, at 19:50, Anthony Foiani wrote:
I'm using boost.interprocess to build a map from string to string that can be shared between multiple processes, with all read/write access protected by a mutex. I'm having a hard time making it work.
Thanks to some helpful folks on freenode #boost pointing out the obvious, I got it working. My main mental block was not realizing that boost::interprocess::basic_string is just another basic_string implementation; it's structured to work better in shared memory, but the default instantiation is just a plain string (no fancy shared memory bits). Thanks for the great library! Regards, Tony
participants (2)
-
Anthony Foiani
-
Tkil