C++ Client API Reference for Oracle Coherence
14c (14.1.2.0.0)

F79659-03

coherence/util/ThreadGate.hpp

00001 /*
00002  * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
00003  *
00004  * Licensed under the Universal Permissive License v 1.0 as shown at
00005  * http://oss.oracle.com/licenses/upl.
00006  */
00007 #ifndef COH_THREAD_GATE_HPP
00008 #define COH_THREAD_GATE_HPP
00009 
00010 #include "coherence/lang.ns"
00011 
00012 #include "coherence/native/NativeAtomic32.hpp"
00013 
00014 COH_OPEN_NAMESPACE2(coherence,util)
00015 
00016 using coherence::native::NativeAtomic32;
00017 
00018 
00019 /**
00020 * Use this class in cases that large numbers of threads can operate
00021 * concurrently with an additional requirement that all threads be blocked for
00022 * certain operations.  The algorithm is based on a gate concept, allowing
00023 * threads in (enter) and out (exit), but occasionally shutting the gate (close)
00024 * such that other threads cannot enter and exit.  However, since threads may
00025 * "be inside", the gate cannot fully close until they leave (exit).  Once all
00026 * threads are out, the gate is closed, and can be re-opened (open) or
00027 * permanently closed (destroy).
00028 *
00029 * Each call to enter requires a corresponding call to exit, similar to the
00030 * implementation of the COH_SYNCHRONIZED macro that calls Object::lock at the
00031 * the beginning of the synchronized portion and protects the synchronized
00032 * portion with a try..catch construct that ensures the execution of a
00033 * Object::unlock call.  For example, the following would ensure proper clean-up
00034 * using a ThreadGate:
00035 * </p>
00036 * The enter/exit calls can be nested; the same thread can invoke enter multiple
00037 * times as long as exit is invoked a corresponding number of times. The
00038 * close/open calls work in the same manner.  Lastly, the thread that closes the
00039 * gate may continue to enter/exit the gate even when it is closed since that
00040 * thread has exclusive control of the gate.
00041 * <p>
00042 * To make usage of these calls easier, the following macros have been defined:
00043 * <ul>
00044 *     <li> COH_GATE_ENTER enters and automatically exits the gate
00045 *     <li> COH_GATE_CLOSE closes and automatically opens the gate
00046 *     <li> COH_GATE_BAR   bars entry and automatically opens the gate
00047 * </ul>
00048 * <pre>
00049 * COH_GATE_ENTER (hGate) // read lock acquired
00050 *   {
00051 *   // read operations go here
00052 *   // ...
00053 *   // ...
00054 *   } // read lock released
00055 * // outside of sync block
00056 *
00057 * COH_GATE_CLOSE (hGate) // write lock acquired
00058 *   {
00059 *   // write operations go here
00060 *   // ...
00061 *   // ...
00062 *   } // write lock released
00063 * // outside of sync block
00064 *
00065 * COH_GATE_BAR (hGate) // additional readers are blocked
00066 *   {
00067 *   // non-synchronized ops
00068 *   COH_GATE_CLOSE (hGate) // write lock acquired
00069 *      {
00070 *      // ...
00071 *      // ...
00072 *      } // inner-write lock released
00073 *   // gate still locked
00074 *   } // gate opened
00075 * // outside of sync block
00076 * </pre>
00077 *
00078 * @author nsa  2008.01.03
00079 */
00080 class COH_EXPORT ThreadGate
00081     : public class_spec<ThreadGate>
00082     {
00083     friend class factory<ThreadGate>;
00084 
00085     // ----- enum: State ----------------------------------------------------
00086 
00087     public:
00088     /**
00089     * State identifiers
00090     */
00091     typedef enum
00092         {
00093         gate_open      = 0,
00094         gate_closing   = 1,
00095         gate_closed    = 2,
00096         gate_destroyed = 3
00097         } Status;
00098 
00099 
00100     // ----- constructor ----------------------------------------------------
00101 
00102     protected:
00103         /**
00104         * Create a new ThreadGate.
00105         */
00106         ThreadGate();
00107 
00108 
00109     // ----- ThreadGate interface -------------------------------------------
00110 
00111     public:
00112         /**
00113         * Bar entry of the thread gate by other threads, but do not wait for
00114         * the gate to close. When all other threads have exited, the thread
00115         * gate will be closeable by the thread which barred entry. Each
00116         * successful invocation of this method must ultimately have a
00117         * corresponding invocation of the open() method (assuming the thread
00118         * gate is not destroyed), even if the calling thread does not
00119         * subsequently close the gate.
00120         *
00121         * @param cMillis  maximum number of milliseconds to wait; pass
00122         *                 infinite for forever or immediate for no wait
00123         *
00124         * @return true iff entry into the gate was successfully barred by the
00125         *              calling thread
00126         */
00127         virtual bool barEntry(int64_t cMillis = infinite);
00128 
00129         /**
00130         * Close the thread gate. A thread uses this method to obtain exclusive
00131         * access to the resource represented by the thread gate. Each
00132         * invocation of this method must ultimately have a corresponding
00133         * invocation of the open() method.
00134         *
00135         * @param cMillis  maximum number of milliseconds to wait; pass
00136         *                 infinite for forever or immediate for no wait
00137         *
00138         * @return true iff the entry into the thread gate was successfully
00139         *              barred by the calling thread and no other threads
00140         *              remain in the gate.
00141         */
00142         virtual bool close(int64_t cMillis = infinite);
00143 
00144         /**
00145         * Destroy the thread gate. This method can only be invoked if the
00146         * gate is already closed by the calling thread.
00147         */
00148         virtual void destroy();
00149 
00150         /**
00151         * Enter the thread gate. A thread uses this method to obtain
00152         * non-exclusive access to the resource represented by the thread gate.
00153         * Each successful invocation of this method must ultimately have a
00154         * corresponding invocation of the exit() method.
00155         *
00156         * @param cMillis  maximum number of milliseconds to wait; pass
00157         *                 infinite for forever or immediate for no wait
00158         *
00159         * @return true iff the calling thread successfully entered the gate
00160         */
00161         virtual bool enter(int64_t cMillis = infinite);
00162 
00163         /**
00164         * Exit the gate. A thread must invoke this method corresponding to
00165         * each successful invocation of the enter method.
00166         */
00167         virtual void exit();
00168 
00169         /**
00170         * After entry into the ThreadGate is restricted by a call to
00171         * barEntry() or close(), it can be re-opened by calling this method.
00172         * Only the thread that called barEntry() or close() can call open().
00173         */
00174         virtual void open();
00175 
00176         /**
00177         * Return the number of entered threads.
00178         *
00179         * @return the number of entered threads
00180         */
00181         virtual int32_t getActiveCount() const;
00182 
00183         /**
00184         * Determine if the current thread has entered and not exited. This is
00185         * useful for detecting re-entrancy.
00186         *
00187         * @return true if the current thread has entered and not exited.
00188         */
00189         virtual bool isActiveThread() const;
00190 
00191         /**
00192         * Return the number of unmatched completed close/barEntry calls.
00193         *
00194         * @return the number of unmatched completed close/barEntry calls.
00195         */
00196         virtual int32_t getCloseCount() const;
00197 
00198         /**
00199         * Return the current thread gate status.
00200         *
00201         * @return the current thread gate status
00202         */
00203         virtual Status getStatus() const;
00204 
00205 
00206     // ----- Object interface -----------------------------------------------
00207 
00208     public:
00209         /**
00210         * {@inheritDoc}
00211         */
00212         virtual TypedHandle<const String> toString() const;
00213 
00214 
00215     // ----- inner class: Counter -------------------------------------------
00216 
00217     public:
00218         /**
00219         * Counter is a mutable integer class.
00220         */
00221         class Counter
00222             : public class_spec<Counter>
00223             {
00224             friend class factory<Counter>;
00225 
00226             // ----- constructor ----------------------------------------
00227 
00228             protected:
00229                 /**
00230                 * Create a Counter initialized with a specified value.
00231                 *
00232                 * @param c  the initial value of the Counter
00233                 */
00234                 Counter(int32_t c = 0);
00235 
00236             // ----- Counter interface ----------------------------------
00237 
00238             public:
00239                 /**
00240                 * Return the count.
00241                 *
00242                 * @return the count
00243                 */
00244                 virtual int32_t getCount() const;
00245 
00246                 /**
00247                 * Set the count.
00248                 *
00249                 * @param c  the value to set the count to.
00250                 */
00251                 virtual void setCount(int32_t c);
00252 
00253                 /**
00254                 * Increment the count by 1.
00255                 *
00256                 * @return the incremented count.
00257                 */
00258                 virtual int32_t increment();
00259 
00260                 /**
00261                 * Decrement the count.
00262                 *
00263                 * @return the decremented count.
00264                 */
00265                 virtual int32_t decrement();
00266 
00267             // ----- Object interface -----------------------------------
00268 
00269             public:
00270                 /**
00271                 * {@inheritDoc}
00272                 */
00273                 virtual TypedHandle<const String> toString() const;
00274 
00275             // ----- data members ---------------------------------------
00276 
00277             private:
00278                 /**
00279                 * The count.
00280                 */
00281                 int32_t m_c;
00282             };
00283 
00284 
00285     // ----- inner class: GateBlock -----------------------------------------
00286 
00287     public:
00288         /**
00289         * The EnterBlock class allows for easy creation of ThreadGate::enter
00290         * code. The EnterBlock object will ensure that the gate is entered
00291         * and exited as a part of starting and ending the code block. It's
00292         * used by the COH_GATE_ENTER macro
00293         */
00294         class GateBlock
00295             {
00296             // ----- enums ----------------------------------------------
00297             public:
00298                 /**
00299                 * The type of GateBlock that will be constructed
00300                 */
00301                 typedef enum
00302                     {
00303                     bar,
00304                     close,
00305                     enter
00306                     } BlockType;
00307 
00308             // ----- constructor ----------------------------------------
00309 
00310             public:
00311                 /**
00312                 * Construct a new EnterBlock object entering the supplied
00313                 * gate.
00314                 *
00315                 * @param nType  the type of GateBlock to construct
00316                 * @param hGate  the gate to enter
00317                 * @param lTime  maximum number of milliseconds to wait; pass
00318                 *               infinite for forever or immediate for no wait
00319                 */
00320                 GateBlock(BlockType nType, ThreadGate::Handle hGate,
00321                         int64_t lTime);
00322 
00323                 /**
00324                 * Copy constructor used by the COH_GATE_ENTERED macro.
00325                 *
00326                 * The new block takes over ownership of the gate.
00327                 */
00328                 GateBlock(const GateBlock& that);
00329 
00330                 /**
00331                 * Destroy an EnterBlock object, exiting the associated gate
00332                 */
00333                 ~GateBlock();
00334 
00335             // ----- GateBlock interface --------------------------------
00336 
00337             public:
00338                 /**
00339                 * Boolean conversion for the COH_GATE_ENTER macro
00340                 *
00341                 * @return true always
00342                 *
00343                 * @throw IllegalStateException if the gate is null
00344                 */
00345                 operator bool() const;
00346 
00347             private:
00348                 /**
00349                 * Blocked assignment operator.
00350                 */
00351                 const GateBlock& operator=(const GateBlock&);
00352 
00353                 /**
00354                 * Blocked dynamic allocation.
00355                 */
00356                 static void* operator new(size_t);
00357 
00358             // ----- data members ---------------------------------------
00359 
00360             protected:
00361                 /**
00362                 * Gate used by the EnterBlock
00363                 */
00364                 mutable ThreadGate::Handle m_hGate; // on stack
00365 
00366                 /**
00367                 * The operation requested when the GateBlock is entered.
00368                 */
00369                 BlockType m_nType;
00370             };
00371 
00372     // ----- helper methods -------------------------------------------------
00373 
00374     protected:
00375         /**
00376         * Specify the number of unmatched completed close/barEntry calls. The
00377         * caller must have the gate closed/closing.
00378         *
00379         * @param cClose  the number of unmatched completed close/barEntry
00380         *                calls.
00381         */
00382         virtual void setCloseCount(int32_t cClose);
00383 
00384         /**
00385         * Return the thread that is closing the gate.
00386         *
00387         * @return the thread that is closing the gate
00388         */
00389         virtual Thread::View getClosingThread() const;
00390 
00391         /**
00392         * Specify the thread id that is closing the gate. The caller must be
00393         * synchronized on the thread gate.
00394         *
00395         * @param vThread  the thread id that is closing the gate.
00396         */
00397         virtual void setClosingThread(Thread::View vThread);
00398 
00399         /**
00400         * Update the current thread gate status, without changing the active
00401         * count. The caller must hold synchronization on the ThreadGate.
00402         *
00403         * @param nStatus  the new status
00404         *
00405         * @return the old status
00406         */
00407         virtual Status updateStatus(Status nStatus);
00408 
00409         /**
00410         * Wait up to the specified number of milliseconds for notification.
00411         * Caller must be synchronized on this gate.
00412         *
00413         * @param cMillis  the number of milliseconds to wait;; pass
00414         *                 infinite for forever or immediate for no wait
00415         *
00416         * @return the remaining wait time in milliseconds
00417         */
00418         virtual int64_t doWait(int64_t cMillis);
00419 
00420     private:
00421         /**
00422         * Perform cleanup related to returning from the close() method.
00423         *
00424         * @param  fReenter  true iff the calling thread needs to reenter the
00425         *                   gate
00426         * @param  fReopen   true iff the calling thread needs to reopen the
00427         *                   gate
00428         */
00429         void closeFinally(bool fReenter, bool fReopen);
00430 
00431         /**
00432         * Perform cleanup related to returning from the enter() method.
00433         *
00434         * @param hCounter  the thread-local counter
00435         * @param fSuccess  true iff the gate was successfully entered
00436         */
00437         void enterFinally(Counter::Handle hCounter, bool fSuccess);
00438 
00439         /**
00440         * Return the thread local counter object.
00441         *
00442         * @return the thread local counter object
00443         */
00444         Counter::Handle getCounter() const;
00445 
00446 
00447     // ----- data members ---------------------------------------------------
00448 
00449     public:
00450         /**
00451         * The maximum number of threads allowed in the gate at one time.
00452         */
00453         static const int32_t max_enters = 0x3FFFFFFF;
00454 
00455         /**
00456         * The constant representing wait forever.
00457         */
00458         static const int64_t infinite = int64_t(-1);
00459 
00460         /**
00461         * The constant representing not to wait.
00462         */
00463         static const int64_t immediate = int64_t(0);
00464 
00465     private:
00466         /**
00467         * The state of the ThreadGate. This counter is overloaded for two
00468         * responsibilities: It tracks the number of threads that have
00469         * entered the gate, and the status of the gate (OPEN, CLOSING
00470         * CLOSED or DESTROYED).
00471         */
00472         NativeAtomic32 m_nAtomicState;
00473 
00474         /**
00475         * Number of unmatched completed close/barEntry calls.
00476         */
00477         int32_t m_cClose;
00478 
00479         /**
00480         * The id of the thread that's currently closing the gate.
00481         */
00482         MemberView<Thread> m_vClosingThread;
00483 
00484         /**
00485         * Count of unmatched enter calls per thread.
00486         */
00487         mutable FinalHandle<ThreadLocalReference> f_htlcEnters;
00488     };
00489 
00490 
00491 // ----- non-member operators and functions ---------------------------------
00492 
00493 /**
00494 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for
00495 * more details.
00496 */
00497 #define COH_GATE_ENTER(GATE, TIME) \
00498     if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) =  \
00499             coherence::util::ThreadGate::GateBlock(                         \
00500                 coherence::util::ThreadGate::GateBlock::enter, GATE, TIME))
00501 
00502 /**
00503 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for
00504 * more details.
00505 */
00506 #define COH_GATE_BAR(GATE, TIME) \
00507     if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) =  \
00508             coherence::util::ThreadGate::GateBlock(                         \
00509                 coherence::util::ThreadGate::GateBlock::bar, GATE, TIME))
00510 /**
00511 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for
00512 * more details.
00513 */
00514 #define COH_GATE_CLOSE(GATE, TIME) \
00515     if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) =  \
00516             coherence::util::ThreadGate::GateBlock(                         \
00517                 coherence::util::ThreadGate::GateBlock::close, GATE, TIME))
00518 
00519 COH_CLOSE_NAMESPACE2
00520 
00521 #endif // COH_THREAD_GATE_HPP
Copyright © 2000, 2025, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.