00001 /* 00002 * SynchronizedMemberWriteBlock.hpp 00003 * 00004 * Copyright (c) 2000, 2013, 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