Boost logo

Boost Users :

Subject: [Boost-users] [interprocesss] managed_mapped_file mutex question
From: Andy Wiese (andyw_at_[hidden])
Date: 2010-03-18 11:55:09


This is a somewhat different take on the question I asked earlier
about interprocess mutexes in allocators.

I am using a default interprocess::managed_mapped_file to hold a index
for a multiprocess property store.

There is one object named "index" in the mapped file, which is an
interprocess::map.
The map holds an interprocess::set of fixed-length strings. (I had an
allocation problem with sets of string objects, but that's another
topic)

Many processes will both read and write this index map. Do the
interprocess:: containers provide the needed synchronization, or do I
need other synchronization mechanisms?

If I am reading the docs correctly, it seems to say that I don't need
additional synchronization if I am not adding/removing named objects.
However, my tests break with multiple processes. I don't know if I
just need my own synchronization or if a deeper problem is implied.

Following is the simple test I have been using. Works with one
process, breaks with two concurrent.
(os-x 10.5, boost trunk)

Thanks in advance for any advice!

Andy

-------------------------------------------------------
namespace bip = boost::interprocess;

typedef struct { char t[64]; } thing_t;
struct ThingLess {
  bool operator()(thing_t const & lhs, thing_t const & rhs) const {
    return (strcmp(lhs.t, rhs.t) < 0);
  }
};

typedef bip::managed_mapped_file
shared_store_t;
typedef shared_store_t::segment_manager
segment_manager_t;
typedef bip::allocator<void, segment_manager_t>
void_allocator_t;
typedef bip::allocator<char, segment_manager_t>
char_allocator_t;
typedef bip::basic_string<char, std::char_traits<char>,
char_allocator_t> char_string_t;
typedef bip::allocator<char_string_t, segment_manager_t>
char_string_allocator_t;

typedef bip::allocator<thing_t, segment_manager_t> thing_allocator_t;
typedef bip::set<thing_t, ThingLess, thing_allocator_t> thing_set_t;
typedef std::pair<const char_string_t, thing_set_t> map_value_t;
typedef bip::allocator<map_value_t, segment_manager_t>
map_value_allocator_t;
typedef bip::map< char_string_t, thing_set_t,
std::less<char_string_t>, map_value_allocator_t> index_map_t;

int main(int argc, char* argv[])
{
  //fork(); // forking here will usually cause a bus error
  int pid = getpid();

  // find or create the mapped file
  std::auto_ptr<shared_store_t> store(new
shared_store_t(bip::open_or_create, "/tmp/testindex", 1024*1024));
  void_allocator_t allocator(store->get_segment_manager());
  // find or create the index object
  index_map_t* index = store->get_segment_manager()-
>find<index_map_t>("index").first;
  if (!index) {
    index = store->construct<index_map_t>("index")
(std::less<char_string_t>(), allocator); assert(index);
  }

  // add pairs to the map, find them, remove them.
  for (int j=0; j<1000; ++j) {
    for (int i=0; i<100; ++i) {
      try {
        std::ostringstream ks; ks << "key" << i;
        std::ostringstream ts; ts << "thing" << i;

        // look for thing in map
        char_string_t key(ks.str().c_str(), allocator);
        index_map_t::iterator foundIt = index->find(key);
        if (foundIt == index->end()) {
          // add thing to map
          thing_t thing;
          strcpy(thing.t,ts.str().c_str());
          thing_set_t thingSet(ThingLess(), allocator);
          thingSet.insert(thing);
          map_value_t entry(key,thingSet);
          index->insert(entry);
          std::cout << pid << " Added " << key << std::endl;
        }
        // look again...
        foundIt = index->find(key);
        if (foundIt != index->end()) {
          if (ts.str() == foundIt->second.begin()->t) {
            std::cout << pid << " FOUND " << key << ":"<< foundIt-
>second.begin()->t << std::endl;
          } else {
            std::cout << pid << " FAILED? " << key << ":"<< foundIt-
>second.begin()->t << std::endl;
          }
        }
        if (j%2) {
          // erase thing from map, every other pass just for some
variety
          index->erase(key);
          std::cout << pid << " Erased " << key << std::endl;
        }
      } catch( bip::bad_alloc & ba ) {
        std::cout << "bad_alloc at " << j<<","<<i<< " "<< ba.what() <<
std::endl;
      } catch(std::exception & e) {
        std::cout << e.what() << std::endl;
      } catch(...) {
        std::cout << "some other exception" << std::endl;
      }
    }
    std::cout << pid << " --------- End Round " << j << " --------- "
<<std::endl;
  }

return 0;
}


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