00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Jeff Lait 00008 * Side Effects Software Inc 00009 * 123 Front Street West, Suite 1401 00010 * Toronto, Ontario 00011 * Canada M5J 2M2 00012 * 416-504-9876 00013 * 00014 * NAME: UT_DoubleLock.h ( UT Library, C++) 00015 * 00016 * COMMENTS: 00017 */ 00018 00019 #ifndef __UT_DoubleLock__ 00020 #define __UT_DoubleLock__ 00021 00022 #include "UT_API.h" 00023 00024 #include "UT_Lock.h" 00025 00026 // 00027 // A double-checked lock. Only locks the thread lock when the value is 0. 00028 // 00029 // This works similar to an AutoLock, but provides a needInit function 00030 // to tell you if you val was false after locking 00031 // 00032 // To use this lock: 00033 // 00034 // UT_Lock theLock; 00035 // 00036 // OBJECT * 00037 // getSingleton() 00038 // { 00039 // volatile static OBJECT *theObj = 0; 00040 // 00041 // UT_DoubleLock<OBJECT *> lock(theLock, theObj); 00042 // 00043 // if (!lock.getValue()) 00044 // { 00045 // lock.setValue(new OBJECT()); 00046 // } 00047 // return lock.getValue(); 00048 // } 00049 // 00050 // NOTE: Do not roll your own double checked lock. Double checked locks 00051 // ideally need machine support to work properly - this implementation 00052 // is theoritically broken. The intent of this class is to make it 00053 // easy to replace DoubleLock with an AutoLock equivalent, allowing 00054 // us to time the cost of using AutoLocks and see if one of these odd 00055 // cases is the source of multi threaded bugs. 00056 // 00057 // You are discouraged from using double checked locks. Consider 00058 // eager evaluation or thread local storage of the cached value 00059 // as preferable alternatives. 00060 // 00061 template <class T> 00062 class UT_DoubleLock 00063 { 00064 public: 00065 UT_DoubleLock(UT_Lock &lock, T &val) 00066 : myLock(lock) 00067 , myValue(val) 00068 , myPendingValue(0) 00069 , myIsLocked(false) 00070 , myNeedInit(false) 00071 { 00072 if (!val) 00073 { 00074 myLock.lock(); 00075 myIsLocked = true; 00076 if (!val) 00077 myNeedInit = true; 00078 } 00079 } 00080 00081 ~UT_DoubleLock() 00082 { 00083 if (myIsLocked) 00084 { 00085 if (myNeedInit) 00086 { 00087 UT_ASSERT_P(myPendingValue); 00088 myValue = myPendingValue; 00089 } 00090 myLock.unlock(); 00091 } 00092 } 00093 00094 T getValue() 00095 { 00096 if (myPendingValue) 00097 return myPendingValue; 00098 return myValue; 00099 } 00100 void setValue(T val) 00101 { 00102 UT_ASSERT_P(myNeedInit); 00103 myPendingValue = val; 00104 } 00105 00106 private: 00107 UT_Lock &myLock; 00108 T &myValue; 00109 T myPendingValue; 00110 bool myIsLocked; 00111 bool myNeedInit; 00112 }; 00113 00114 #endif 00115
1.5.9