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