Hi Joaquin, I have to use actually two or more threads on procedure pool. I start seeing same Problem when I have three/four threads working on same procedure pool. I tried to introduce mutex (ACE_Guard) but still having problems in execution in one/two minute of execution. Seems I am guarding every method that is used by container. Anything wrong with the Following code? Thanks Priyank #ifndef PROCEDURE_POOL_H #define PROCEDURE_POOL_H /** * Identifier pool of procedure. This procedure will be un-sorted * hashed index provided by procedures unique id retuned by procedure. * It internally uses boost hashed index for indexing the procedures * in procedure pool. * * @author Priyank Patel * @since Mar 30, 2006 */ #include <ace/Mutex.h> #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/hashed_index.hpp> #include <boost/config.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> #include <boost/multi_index/key_extractors.hpp> #include "Procedure.h" using boost::multi_index_container; using namespace boost::multi_index; /** * Defines tag used for procedure id. */ struct procedure_id_tag { }; class Procedure_Pool: boost::noncopyable { private: /** * Type definition for multi index container. */ typedef multi_index_container< Procedure*, indexed_by< hashed_unique< tag<procedure_id_tag>, const_mem_fun<Procedure, int, &Procedure::id> > > > Procedure_Hashed_Pool; /** * Type definition for indexing based on procedure id tag. */ typedef Procedure_Hashed_Pool::index<procedure_id_tag>::type Procedure_By_Id; public: /** * Constructor. */ Procedure_Pool(): pool_(), procedure_by_id_(pool_.get<procedure_id_tag>()) { } /** * Adds specified procedure in this pool. * It will intenally used procedures id() method to index procedure. * @param _procedure Procedure to be added in this pool * @return Success (0) or Failure (-1) based on addition happened or not */ int add_by_id(Procedure * _procedure); /** * Removes procedure from this pool. * @param _procedure procedure that needs to be removed * @return Success (0) or Failure (1) based on removal happend or not */ int remove_by_id(Procedure * _procedure); /** * Retrieves procedure based on specified id. * @param _id Identifier * @return Procedure Pointer to procedure. Returns 0 if procedure not found */ Procedure * find_by_id(int _id); private: /** * Returns true if procedure is present otherwise returns false. * @param _procedure procedure that needs to found * @return true if found or false if not found */ //bool find_by_id(Procedure * _procedure); /** * boost multiindex object that is associated with this pool. */ Procedure_Hashed_Pool pool_; /** * Refernece of pool that is indexed by procedure id tag. */ Procedure_By_Id &procedure_by_id_; ACE_Mutex mutex_; }; #endif //===============================================================================/// #include "../include/Procedure_Pool.h" int Procedure_Pool::add_by_id(Procedure * _procedure) { LD_TRACE("Procedure_Pool::add_by_id"); ACE_ASSERT(_procedure != 0); ACE_DEBUG((LM_DEBUG, "ADDING %d\n", _procedure->id())); if (find_by_id(_procedure->id()) == 0) { ACE_Guard<ACE_Mutex> guard(mutex_); { // procedure not found procedure_by_id_.insert(_procedure); } // debug info ACE_DEBUG((LM_DEBUG, "Added procedure : %d \n", _procedure->id())); // return success return 0; } else { // error ACE_ERROR((LD_ERROR "%N:%l Error in adding procedure : %d \n", _procedure->id())); // return failure return -1; } } int Procedure_Pool::remove_by_id(Procedure * _procedure) { LD_TRACE("Procedure_Pool::remove_by_id"); ACE_ASSERT(_procedure != 0); ACE_DEBUG((LM_DEBUG, "REMOVING: %d \n", _procedure->id())); if (find_by_id(_procedure->id()) != 0) { ACE_Guard<ACE_Mutex> guard(mutex_); { // procedure found procedure_by_id_.erase(_procedure->id()); } ACE_DEBUG((LM_DEBUG, "Removed procedure : %d \n", _procedure->id())); return 0; } else { ACE_ERROR((LD_ERROR "%N:%l Error in removing procedure : %d \n", _procedure->id())); return -1; } } Procedure * Procedure_Pool::find_by_id(int _id) { LD_TRACE("Procedure_Pool::find_by_id"); ACE_Guard<ACE_Mutex> guard(mutex_); { Procedure_By_Id::iterator it = procedure_by_id_.find(_id); if (it != procedure_by_id_.end()) { ACE_DEBUG((LM_DEBUG, "%N:%l Found procedure for id: %d \n", _id)); return *it; } } ACE_DEBUG((LM_DEBUG, "%N:%l Not able to found procedure for id: %d \n", _id)); // return null return 0; } -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of JOAQUIN LOPEZ MU?Z Sent: Thursday, May 11, 2006 2:12 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] [multi_index] thread safety ----- Mensaje original ----- De: george <george13p@yahoo.com> Fecha: Jueves, Mayo 11, 2006 7:27 pm Asunto: Re: [Boost-users] [multi_index] thread safety
hello Joaquin
Hello George,
You have to lockguard every access to the container; note this also includes, for instance, container traversal with iterators, i.e. iterator displacement. Strictly speaking, iterator dereference should also be lockguarded, although I can say unofficially that unguarded dereference is OK.
can you explain a litle more? as I konw from STL, multiple readers is ok.
Correct.
reading and inserting a new object does't invalidate iterators(for pointer-based conteiners offcourse,list, map etc...)
Correct. This also holds for multi_index_containers.
a concurrent read and insert in multi_index are not (safely)possible? I mean there might be an iterator invalidation?
Concurrent reading and writing is not safe, but the issue has nothing to do with iterator invalidation. ...I think I've got a hunch about what you've got in mind. When I say that you've got to lockguard iterator displacement, what I mean is: consider a concurrent write operation and an iterator increment; this concurrency is not thread safe and undefined behavior results: a possible outcome is iterator invalidation, but you could also get an app crash, a corrupted data structure, an infinite loop or whatever. Tecnhically speaking, an invalid iterator is a perfectly legal state for an iterator to be in, which has nothing to do with undefined behavior resulting from violating thread safety guarantees. I'm not sure I made myself clear :) Insist on me if I didn't.
offcourse there is a chance for a 'dirty-read' but this for the domain of the aplication if it is a problem and not for multi_index.
I don't get what you mean here, would you care to elaborate? Joaquín M López Muñoz Telefónica, Investigación y Desarrollo _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users