2

I have the following program and this is what it is supposed to do:

  • open/create a shared memory segment
  • call find() on that managed shared memory segment to look for an object
  • if not found, instantiate it
  • if found, just dump the contents

I test it the following way:

  • run one instance of this program in one window
  • it creates the shared mem segment and also instantiates the object
  • waits forever (not sure if this is needed, just added it to make sure linux doesn't free that shared memory as soon as the program exits)
  • run another instance of the same program and expect it to find the object (and this is where it gets stuck)

    class data_store {
    public:
        data_store(uint32_t id, const char *name, bool safe) {
            id_ = id;
            strncpy(name_, name, sizeof(name_));
            safe_ = safe;
        }
        ~data_store() {}
        uint32_t id(void) const { return id_; }
        const char *name(void) const { return name_; }
    
    private:
        char name_[32];
        bool safe_;
        uint32_t id_;
    };
    int
    main ()
    {
        managed_shared_memory    *test_shmseg;
        data_store               *ds;
    
        try {
            test_shmseg = new managed_shared_memory(open_or_create, "seg2", 2048);
        } catch (std::exception ex) {
            std::cerr << ex.what() << '\n';
        }
        assert(test_shmseg != NULL);
    
        try {
            std::cout << "Free size " << test_shmseg->get_free_memory() << std::endl;    
            std::pair<data_store *, std::size_t> dsdir =
                test_shmseg->find<data_store>("Datastore");
            if (dsdir.first == NULL) {
                // instantiate a data store
                std::cout << "Instantiating data store" << std::endl;
                ds =
                    test_shmseg->construct<data_store>("DataStore")(1,
                                                                    std::string("ds").c_str(), true);
                if (ds == NULL) {
                    std::cout << "Failed to construct Datastore" << std::endl;
                    exit(1);
                }
            } else {
                std::cout << "Datastore found" << std::endl;
                ds = dsdir.first;
            }
            std::cout << "Data store id " << ds->id() << std::endl;
            std::cout << "Data store name " << ds->name() << std::endl;
        }  catch (boost::interprocess::bad_alloc &ex) {
            std::cerr << ex.what() << '\n';
        }
        while (1);   // wait for the other instance of this program to find the created segment and dump contents
    }
    

    I am unable to figure out why the 2nd instance of this is able to open the shared memory segment but always stuck on a mutex

    (gdb) bt
    #0  0x00007ffff7bcd42d in __lll_lock_wait () from /lib64/libpthread.so.0
    #1  0x00007ffff7bc8de6 in _L_lock_870 () from /lib64/libpthread.so.0
    #2  0x00007ffff7bc8cdf in pthread_mutex_lock () from /lib64/libpthread.so.0
    #3  0x0000000000403d6d in boost::interprocess::ipcdetail::posix_recursive_mutex::lock (this=0x7ffff7ff8070)
        at /usr/include/boost/interprocess/sync/posix/recursive_mutex.hpp:90
    #4  0x0000000000403e52 in boost::interprocess::interprocess_recursive_mutex::lock (this=0x7ffff7ff8070)
        at /usr/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp:163
    #5  0x0000000000408457 in boost::interprocess::scoped_lock<boost::interprocess::interprocess_recursive_mutex>::lock
        (this=0x7fffffffdf30) at /usr/include/boost/interprocess/sync/scoped_lock.hpp:284
    #6  0x00000000004073b0 in boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::interprocess::iset_index>::priv_get_lock (this=0x7ffff7ff8010, use_lock=true)
        at /usr/include/boost/interprocess/segment_manager.hpp:1315
    #7  0x00000000004069ea in boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::interprocess::iset_index>::priv_generic_find<char> (this=0x7ffff7ff8010, name=0x41c4a5 "Datastore", index=..., table=...,
        length=@0x7fffffffe098: 0, is_intrusive=..., use_lock=true)
        at /usr/include/boost/interprocess/segment_manager.hpp:844
    #8  0x0000000000405f1e in boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::interprocess::iset_index>::priv_find_impl<data_store> (this=0x7ffff7ff8010, name=0x41c4a5 "Datastore", lock=true)
        at /usr/include/boost/interprocess/segment_manager.hpp:724
    #9  0x0000000000405309 in boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::interprocess::iset_index>::find<data_store> (this=0x7ffff7ff8010, name=...)
        at /usr/include/boost/interprocess/segment_manager.hpp:434
    #10 0x00000000004044ea in boost::interprocess::ipcdetail::basic_managed_memory_impl<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::interprocess::iset_index, 16ul>::find<data_store> (this=0x63ec20, name=...)
        at /usr/include/boost/interprocess/detail/managed_memory_impl.hpp:346
    #11 0x00000000004040f7 in boost::interprocess::basic_managed_shared_memory<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void, long, unsigned long, 0ul>, 0ul>, boost::int---Type <return> to continue, or q <return> to quit---
    erprocess::iset_index>::find<data_store> (this=0x63ec20, name=...)
        at /usr/include/boost/interprocess/managed_shared_memory.hpp:212
    

Any help is appreciated.

S.K
  • 347
  • 1
  • 6
  • 20

1 Answers1

1
  • waits forever (not sure if this is needed, just added it to make sure linux doesn't free that shared memory as soon as the program exits)

No that's not required. Shared memory is shared. It stays unless you explicitly remove() it.

Review

You have at least one inconsistency: the name of the object is either "Datastore" or "DataStore" - make sure you match the spelling.

Other than that, I think

  • you might not want "array-style" allocation, which you are (inadvertently?) using
  • you might be better off using find_or_construct which does remove the potential race-condition (time-of-check vs time-of-use window between finding and creating a new instance, respectively).

Other than that I don't see any immediate reason for a hang. Perhaps you can try by removing the shared object once, manually, and using the following simplified program to re-test:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
#include <cassert>
namespace bip = boost::interprocess;

class data_store {
  public:
    data_store(uint32_t id, const char *name, bool safe) :
        id_(id), safe_(safe)
    {
        id_ = id;
        assert(name && strlen(name) < (sizeof(name_)-1));
        strncpy(name_, name, sizeof(name_));
        safe_ = safe;
    }

    uint32_t   id()    const { return id_; }
    const char *name() const { return name_; }

  private:
    char name_[32] = {0};
    uint32_t id_;
    bool safe_;
};

int main () try {
    bip::managed_shared_memory seg(bip::open_or_create, "seg2", 2048);
    data_store ds = *seg.find_or_construct<data_store>("DataStore")(1, "ds", true);
    std::cout << "Free size " << seg.get_free_memory() << std::endl;    
    std::cout << "Data store name " << ds.name() << std::endl;
} catch (std::exception ex) {
    std::cerr << ex.what() << '\n';
}

It contains a few style fixes as well as the extra assert on name length.

Live On Coliru

Note: On Coliru using managed_mapped_file instead because manged_shared_memory is not available on Coliru.

Prints:

Free size 1712
Data store name ds
-rw-r--r-- 1 2001 2000 2.0K Mar  5 12:26 seg2
Free size 1712
Data store name ds
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks.. this worked.. i removed the existing segment and fixed the name of the object to be consistent between DataStore/Datastore and that worked. I was expecting to not get stuck like that if the object doesn't exist already. – S.K Mar 06 '18 at 01:15
  • If removing the segment was the essential step, it might mean you have had a process crashed with the embedded mutex locked. There's no real (portable) solution for this: https://stackoverflow.com/questions/15772768/boost-interprocess-mutexes-and-checking-for-abandonment – sehe Mar 06 '18 at 01:16