Oracle Coherence for C++ API
Release 3.6.0.0

E15728-01

coherence/lang/SynchronizedMemberReadBlock.hpp

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