Oracle Coherence for C++ API
Release 3.6.1.0
E18813-01

- Main Page
- Namespaces
- Classes
- Files

# coherence/util/ThreadGate.hpp

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

Copyright © 2000, 2010, Oracle and/or its affiliates. All rights reserved.