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