ESF_Proxy_Collection.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 /**
00004  *  @file   ESF_Proxy_Collection.h
00005  *
00006  *  ESF_Proxy_Collection.h,v 1.10 2006/03/15 07:52:21 jtc Exp
00007  *
00008  *  @author Carlos O'Ryan (coryan@cs.wustl.edu)
00009  *
00010  *  http://doc.ece.uci.edu/~coryan/EC/index.html
00011  */
00012 
00013 #ifndef TAO_ESF_PROXY_COLLECTION_H
00014 #define TAO_ESF_PROXY_COLLECTION_H
00015 #include /**/ "ace/pre.h"
00016 
00017 #include "ace/CORBA_macros.h"
00018 
00019 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00020 # pragma once
00021 #endif /* ACE_LACKS_PRAGMA_ONCE */
00022 
00023 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00024 
00025 template<class Target> class TAO_ESF_Worker;
00026 
00027 /**
00028  * @class TAO_ESF_Proxy_Collection
00029  *
00030  * @brief ESF_Proxy_Collection
00031  *
00032  * Many components in an Event Service need to keep a collection
00033  * of proxies; these collections must be able to cope with several
00034  * concurrency issues:
00035  * + Some threads may need to iterate over the collection and
00036  *   invoke a method on each element.  Locking the collection
00037  *   while this is done is not feasible in all cases: under some
00038  *   configurations the same thread that is iterating over the
00039  *   collection may need to make changes to the set.
00040  * + A recursive lock does not solve the concurrency problems
00041  *   because recursive changes to the collection still invalidate
00042  *   the iterators.
00043  *
00044  * There are several solutions to this problem (see the VARIANTS)
00045  * section, and there is no single one that works bests in all
00046  * cases.  As usual, we wish the strategize the protocol used to
00047  * serialize iterations and changes to the collection.  This class
00048  * encapsulates that protocol.
00049  *
00050  * The usual form of the Iterator pattern does not work well in
00051  * this case: in several variants the synchronization protocol and
00052  * the iteration loop must collaborate to work efficiently.
00053  * Exposing an external iterator would require that every other
00054  * component in the system can support all the synchronization
00055  * protocols.   It is possible to hide some of that complexity
00056  * using heavy weight iterators, but their use is ackward,
00057  * specially since the Koening-style iterators have become more
00058  * popular.
00059  *
00060  * Regular member functions are used to insert, remove and update
00061  * members of the collection and to shutdown (i.e. perform final
00062  * cleanup operations).
00063  *
00064  * The class must also collaborate with other components of the
00065  * EC to efficiently and safely perform memory managment of the
00066  * members in the collection.
00067  *
00068  * The PROXY object must be reference counted with the following
00069  * operations:
00070  *
00071  * + _incr_refcnt() - increment the reference count.
00072  * + _decr_refcnt() - decrement the reference count.
00073  *
00074  * = VARIANTS
00075  *
00076  * We identify several sources of variation:
00077  *
00078  * + Immediate_Changes: in this variant the iteration in performed
00079  *   while holding some kind of synchronization primitive, such as a
00080  *   thread mutex, a recursive mutex, a RW lock, etc.
00081  *   This is only useful in configurations where a separate thread
00082  *   dispatches the events, and thus, can only be used with real
00083  *   locks.
00084  * + Copy_On_Read: before performing the iteration the collection
00085  *   is duplicated into a temporary array.  Thus no locks are held
00086  *   during the iteration.  This is a very expensive approach, but
00087  *   useful in many cases.
00088  *   The kind of lock is also strategized in this case.
00089  * + Copy_On_Write: this is very similar to the previous approach,
00090  *   but the collection is only duplicated when a change is required
00091  *   while some thread is performing an iteration.  The iteration
00092  *   continues over the original copy, while the changes are
00093  *   performed in the duplicate.  The new copy of the collection is
00094  *   used for any subsequent operations, the original is discarded
00095  *   when the last thread using it completes its work.
00096  *   This approach optimizes for the case where no changes are
00097  *   is duplicated into a temporary array.  Thus no locks are held
00098  *   during the iteration.  This is a very expensive approach, but
00099  *   useful in many cases.
00100  *   The kind of lock is also strategized in this case.
00101  * + Delayed_Changes: before starting the iteration a counter is
00102  *   incremented, this counter is used to keep track of the number
00103  *   of threads concurrently using the collection.
00104  *   If a thread wants to perform a change to the collection it must
00105  *   first verify that there are no threads iterating over it.  If
00106  *   there are any threads then the thread queues the modification
00107  *   for later execution, using the Command pattern.
00108  *   The kind of lock is strategized, as this approach is used in
00109  *   single threaded configurations.
00110  *   There are two main variations:
00111  *   - An upcall can result in new dispatches: in this case we
00112  *     have to keep track of a the list of current threads using
00113  *     a Set, to avoid dead-locks. The design is not complete,
00114  *     probably similar to the next one.
00115  *   - Otherwise we just need to control the concurrency using the
00116  *     algorithm described below.
00117  *
00118  * It assumes ownership of the proxies added to the collection,
00119  * it increases the reference count.
00120  *
00121  * Locking is provided by derived classes.
00122  */
00123 template<class PROXY>
00124 class TAO_ESF_Proxy_Collection
00125 {
00126 public:
00127   /// destructor
00128   virtual ~TAO_ESF_Proxy_Collection (void);
00129 
00130   /**
00131    * Iterate over the collection and invoke worker->work() for each
00132    * member of the collection.
00133    * This encapsulates
00134    */
00135   virtual void for_each (TAO_ESF_Worker<PROXY> *worker
00136                          ACE_ENV_ARG_DECL) = 0;
00137 
00138   /// Insert a new element into the collection.  The collection assumes
00139   /// ownership of the element.
00140   virtual void connected (PROXY *proxy
00141                           ACE_ENV_ARG_DECL) = 0;
00142 
00143   /**
00144    * Insert an element into the collection.  No errors can be raised
00145    * if the element is already present.
00146    * The collection assumes ownership, i.e. must invoke
00147    * <proxy->_decr_refcnt()> if the element is already present in the
00148    * collection.
00149    */
00150   virtual void reconnected (PROXY *proxy
00151                             ACE_ENV_ARG_DECL) = 0;
00152 
00153   /// Remove an element from the collection.
00154   virtual void disconnected (PROXY *proxy
00155                              ACE_ENV_ARG_DECL) = 0;
00156 
00157   /// The EC is shutting down, must release all the elements.
00158   virtual void shutdown (ACE_ENV_SINGLE_ARG_DECL) = 0;
00159 };
00160 
00161 // ****************************************************************
00162 
00163 TAO_END_VERSIONED_NAMESPACE_DECL
00164 
00165 #if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
00166 #include "orbsvcs/ESF/ESF_Proxy_Collection.cpp"
00167 #endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
00168 
00169 #if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
00170 #pragma implementation ("ESF_Proxy_Collection.cpp")
00171 #endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
00172 
00173 #include /**/ "ace/post.h"
00174 #endif /* TAO_ESF_PROXY_COLLECTION_H */

Generated on Thu Nov 9 13:08:13 2006 for TAO_ESF by doxygen 1.3.6