Oracle® Fusion Middleware C++ API Reference for Oracle Coherence
12c (12.2.1.3.0)

E80355-01

coherence/util/ThreadGate.hpp

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