coherence/lang/SynchronizedMemberWriteBlock.hpp

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