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