Boost logo

Boost Users :

From: Patel Priyank-PPATEL1 (priyankpatel_at_[hidden])
Date: 2006-05-12 18:09:57


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_at_[hidden] [mailto:boost-users-bounces_at_[hidden]] On Behalf Of JOAQUIN LOPEZ MU?Z
Sent: Thursday, May 11, 2006 2:12 PM
To: boost-users_at_[hidden]
Subject: Re: [Boost-users] [multi_index] thread safety

----- Mensaje original -----
De: george <george13p_at_[hidden]>
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_at_[hidden]
http://lists.boost.org/mailman/listinfo.cgi/boost-users


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