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

F79659-03

coherence/lang/SynchronizedMemberReadBlock.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_SYNCHRONIZED_MEMBER_READ_BLOCK_HPP
00008 #define COH_SYNCHRONIZED_MEMBER_READ_BLOCK_HPP
00009 
00010 #include "coherence/lang/compatibility.hpp"
00011 
00012 #include "coherence/lang/Object.hpp"
00013 #include "coherence/lang/FinalizableBlock.hpp"
00014 
00015 #include <iostream>
00016 
00017 COH_OPEN_NAMESPACE2(coherence,lang)
00018 
00019 
00020 /**
00021 * The SynchronizedMemberReadBlock class allows for easy creation of
00022 * synchronized code blocks based on an Object's member level read/write lock.
00023 * The SynchronizedMemberBlock object will ensure that the locks are acquired
00024 * and released as part of starting and ending the code block.
00025 *
00026 * Member read/write locks are not a general purpose feature, and should not
00027 * be used to protect blocking calls. They are intended to protect reads and
00028 * writes to data member primitives, and other short non-blocking code
00029 * blocks.
00030 *
00031 * Example usage:
00032 * @code
00033 * // outside of sync block
00034 *     {
00035 *     SynchronizedMemberReadBlock syncRead(self()); // read lock acquired
00036 *     // critical section goes here
00037 *     // ...
00038 *     } // read lock released
00039 * // outside of sync block
00040 * @endcode
00041 *
00042 * A more friendly form is to use the COH_SYNCHRONIZED_MEMBER_READ
00043 * macros. Example usage:
00044 *
00045 * @code
00046 * // outside of sync block
00047 * COH_SYNCHRONIZED_MEMBER_READ // read lock acquired
00048 *   {
00049 *   // critical section goes here
00050 *   // ...
00051 *   // ...
00052 *   } // read lock released
00053 * // outside of sync block
00054 * @endcode
00055 *
00056 * The SynchronizedMemberReadBlock class relies on its creator to ensure that
00057 * the associated Object outlives the scope of the block. The helper macro
00058 * ensures this by only allowing you to create a block for the encompassing
00059 * Object, i.e. "this". If the blocks are manually created then the caller
00060 * must ensure that the associated Object outlives the block.
00061 * '
00062 * Note: This class derives from FinalizableBlock, allowing custom finalizers
00063 * to be registered.  The finalizers will execute after the lock has been
00064 * released.
00065 *
00066 * @author mf 2008.01.29
00067 */
00068 class COH_EXPORT SynchronizedMemberReadBlock
00069         : public FinalizableBlock
00070     {
00071     // ----- constructors ---------------------------------------------------
00072 
00073     public:
00074         /**
00075         * Construct a synchronized SynchronizedMemberReadBlock, acquiring the
00076         * Object's member read lock.
00077         *
00078         * @param o          the Object to lock
00079         * @param pDelegate  SynchronizedMemberReadBlock to delegate to, or
00080         *                   NULL for no delegate
00081         *
00082         * @throws IllegalArgumentException if pSyncDelegate is non-NULL and
00083         *         references a different Object.
00084         */
00085         SynchronizedMemberReadBlock(const Object& o,
00086                 SynchronizedMemberReadBlock* pDelegate = NULL)
00087             : FinalizableBlock(), m_cpObject(NULL)
00088             {
00089             initialize(o, pDelegate);
00090             if (isTerminal())
00091                 {
00092                 o._acquireMemberReadLock();
00093                 }
00094             m_cpObject = &o;
00095             }
00096 
00097         /**
00098         * Destroy a SynchronizedMemberReadBlock.
00099         *
00100         * This is a no-op for a delegating block, otherwise the read lock is
00101         * released.
00102         */
00103         ~SynchronizedMemberReadBlock()
00104             {
00105             const Object* cpObject = m_cpObject;
00106             if (NULL != cpObject && isTerminal())
00107                 {
00108                 try
00109                     {
00110                     cpObject->_releaseMemberReadLock();
00111                     }
00112                 catch (const std::exception& e)
00113                     {
00114                     std::cerr << "Error releasing MemberReadLock: " <<
00115                         e.what() << std::endl;
00116                     }
00117                 }
00118             }
00119 
00120     protected:
00121         /**
00122         * Construct an uninitialized SynchronizedMemberReadBlock.
00123         */
00124         SynchronizedMemberReadBlock()
00125             : FinalizableBlock(), m_cpObject(NULL)
00126             {
00127             }
00128 
00129 
00130     // ----- operators ------------------------------------------------------
00131 
00132     public:
00133         /**
00134         * Validate that the lock is held. The boolean conversion is utilized
00135         * by the COH_SYNCHRONIZED_MEMBER_READ macro.
00136         *
00137         * @throw IllegalStateException if the lock is not held.
00138         *
00139         * @return false always
00140         */
00141         operator bool() const
00142             {
00143             if (NULL == m_cpObject)
00144                 {
00145                 coh_throw_illegal_state("lock not held");
00146                 }
00147             return FinalizableBlock::operator bool();
00148             }
00149 
00150     // -------- SynchronizedMemberReadBlock interface -----------------------
00151 
00152     public:
00153         /**
00154         * Get the value of the specified member, without obtaining
00155         * additional synchronization.
00156         *
00157         * This helper function is only supported on "members" which
00158         * supply a custom two-parameter "get" method utilizing the
00159         * SynchronizedMemberBlock::SynchronizedMemberReadBlock facility.
00160         *
00161         * @param member  the member whose value to get
00162         *
00163         * @return the member's value
00164         */
00165         template<class M> typename M::ConstGetType getMember(const M& member)
00166             {
00167             return member.get(this);
00168             }
00169 
00170         /**
00171         * Get the value of the specified member, without obtaining
00172         * additional synchronization.
00173         *
00174         * This helper function is only supported on "members" which
00175         * supply a custom parameterized "get" method utilizing the
00176         * SynchronizedMemberBlock::SynchronizedMemberReadBlock facility.
00177         *
00178         * @param member  the member whose value to get
00179         *
00180         * @return the member's value
00181         */
00182         template<class M> typename M::GetType getMember(M& member)
00183             {
00184             return member.get(this);
00185             }
00186 
00187     protected:
00188         /**
00189         * Initialize a synchronized SynchronizedMemberReadBlock.
00190         *
00191         * @param o          the Object associated with the block
00192         * @param pDelegate  SynchronizedMemberReadBlock to delegate to, or
00193         *                   NULL for no delegate
00194         *
00195         * @throws IllegalArgumentException if pSyncDelegate is non-NULL and
00196         *         references a different Object.
00197         */
00198         void initialize(const Object& o,
00199                 SynchronizedMemberReadBlock* pDelegate = NULL)
00200             {
00201             FinalizableBlock::initialize(pDelegate);
00202 
00203             if (!isTerminal() && &o != pDelegate->m_cpObject)
00204                 {
00205                 coh_throw_illegal_argument("Object differs from delegate");
00206                 }
00207             }
00208 
00209 
00210     // ----- nested class: Guard --------------------------------------------
00211 
00212     public:
00213         /**
00214         * Simple read lock structure for use in inlining.
00215         */
00216         class COH_EXPORT Guard
00217             {
00218             public:
00219                 Guard(const Object& o)
00220                     : m_o(o)
00221                     {
00222                     acquireMemberReadLock(o);
00223                     }
00224 
00225                 ~Guard()
00226                     {
00227                     releaseMemberReadLock(m_o);
00228                     }
00229 
00230             private:
00231                 const Object& m_o;
00232             };
00233 
00234 
00235     // ----- helper methods -------------------------------------------------
00236 
00237     protected:
00238         /*
00239         * Acquire an Object's read lock
00240         */
00241         static void acquireMemberReadLock(const Object& o)
00242             {
00243             o._acquireMemberReadLock();
00244             }
00245 
00246         /*
00247         * Release an Object's read lock
00248         */
00249         static void releaseMemberReadLock(const Object& o)
00250             {
00251             o._releaseMemberReadLock();
00252             }
00253 
00254 
00255     // ----- data members ---------------------------------------------------
00256 
00257     protected:
00258         /**
00259         * The Object on which the lock is applied.
00260         */
00261         const Object* m_cpObject;
00262     };
00263 
00264 COH_CLOSE_NAMESPACE2
00265 
00266 
00267 /**
00268 * Macro for making more readable synchronized member read code blocks See the
00269 * documentation of SynchronizedMemberReadBlock for a usage example.
00270 *
00271 * @see coherence::lang::SynchronizedMemberReadBlock
00272 */
00273 #define COH_SYNCHRONIZED_MEMBER_READ \
00274     if (coherence::lang::SynchronizedMemberReadBlock coh_synchronized_member_read \
00275         = coherence::lang::SynchronizedMemberReadBlock(Object::self())) \
00276         { \
00277         COH_THROW(coherence::lang::IllegalStateException::create()); \
00278         } \
00279     else
00280 
00281 #endif // COH_SYNCHRONIZED_MEMBER_READ_BLOCK_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.