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