
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; }