Boost logo

Boost Users :

Subject: [Boost-users] [interprocess] shared map of string to string?
From: Anthony Foiani (tkil_at_[hidden])
Date: 2010-01-19 21:50:40


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net