Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // G4ThreadLocalSingleton 26 // G4ThreadLocalSingleton 27 // 27 // 28 // Class description: 28 // Class description: 29 // 29 // 30 // This class implements a thread-private "sin 30 // This class implements a thread-private "singleton". Being thread 31 // private the singleton is not a singleton in 31 // private the singleton is not a singleton in the term, but a different 32 // instance exists for each thread. 32 // instance exists for each thread. 33 // This class is a wrapper around the real obj 33 // This class is a wrapper around the real object that we need to 34 // make singleton. 34 // make singleton. 35 // 35 // 36 // Limitation: 36 // Limitation: 37 // The object that is made thread-private si 37 // The object that is made thread-private singleton should not 38 // contain any thread-local data member. Not 38 // contain any thread-local data member. Note that in general, 39 // if an object is to be thread-private it i 39 // if an object is to be thread-private it is unnecessary to mark 40 // any data-member as G4ThreadLocal. 40 // any data-member as G4ThreadLocal. 41 // 41 // 42 // Performance issues: 42 // Performance issues: 43 // This class uses locks and mutexes. 43 // This class uses locks and mutexes. 44 // 44 // 45 // Example: 45 // Example: 46 // This is the singleton pattern often found 46 // This is the singleton pattern often found in Geant4 (sequential): 47 // class G4Class 47 // class G4Class 48 // { 48 // { 49 // private: 49 // private: 50 // static G4Class* instance; 50 // static G4Class* instance; 51 // G4Class() { ... } 51 // G4Class() { ... } 52 // public: 52 // public: 53 // static G4Class* GetInstance() 53 // static G4Class* GetInstance() 54 // { 54 // { 55 // static G4Class theInstance; 55 // static G4Class theInstance; 56 // if ( instance == nullptr ) instance 56 // if ( instance == nullptr ) instance = &theInstance; 57 // return instance; 57 // return instance; 58 // } 58 // } 59 // }; 59 // }; 60 // This is transformed to the following to i 60 // This is transformed to the following to implement a thread-local 61 // singleton: 61 // singleton: 62 // class G4Class 62 // class G4Class 63 // { 63 // { 64 // private: 64 // private: 65 // static G4ThreadLocal G4Class* instanc 65 // static G4ThreadLocal G4Class* instance; 66 // G4Class() { ... } 66 // G4Class() { ... } 67 // public: 67 // public: 68 // static G4Class* GetInstance() 68 // static G4Class* GetInstance() 69 // { 69 // { 70 // if ( instance == nullptr ) instance 70 // if ( instance == nullptr ) instance = new G4Class; 71 // return instance; 71 // return instance; 72 // } 72 // } 73 // }; 73 // }; 74 // Note that this class also has a memory le 74 // Note that this class also has a memory leak. 75 // 75 // 76 // This class can be used as follows: 76 // This class can be used as follows: 77 // class G4Class 77 // class G4Class 78 // { 78 // { 79 // friend class G4ThreadLocalSingleton<G4C 79 // friend class G4ThreadLocalSingleton<G4Class>; 80 // private: 80 // private: 81 // G4Class() { ... } 81 // G4Class() { ... } 82 // public: 82 // public: 83 // static G4Class* GetInstance() 83 // static G4Class* GetInstance() 84 // { 84 // { 85 // static G4ThreadLocalSingleton<G4Cla 85 // static G4ThreadLocalSingleton<G4Class> instance; 86 // return instance.Instance(); 86 // return instance.Instance(); 87 // } 87 // } 88 // }; 88 // }; 89 // Each thread has its own instance of G4Cla 89 // Each thread has its own instance of G4Class. 90 // Deletion of G4Class instances is done at 90 // Deletion of G4Class instances is done at end of program. 91 // Note the "friend" statement. 91 // Note the "friend" statement. 92 92 93 // Author: A.Dotti, 28 October 2013 93 // Author: A.Dotti, 28 October 2013 94 // ------------------------------------------- 94 // -------------------------------------------------------------------- 95 #ifndef G4TLSSINGLETON_HH 95 #ifndef G4TLSSINGLETON_HH 96 #define G4TLSSINGLETON_HH 1 96 #define G4TLSSINGLETON_HH 1 97 97 >> 98 #include <list> >> 99 98 #include "G4AutoLock.hh" 100 #include "G4AutoLock.hh" 99 #include "G4Cache.hh" 101 #include "G4Cache.hh" 100 #include "G4Backtrace.hh" << 101 #include "G4Threading.hh" << 102 << 103 #include <list> << 104 #include <vector> << 105 #include <functional> << 106 102 107 // Forward declaration. See G4AutoDelete.hh 103 // Forward declaration. See G4AutoDelete.hh 108 // 104 // 109 namespace G4AutoDelete 105 namespace G4AutoDelete 110 { 106 { 111 template <class T> 107 template <class T> 112 void Register(T*); 108 void Register(T*); 113 } 109 } 114 110 115 template <class T> 111 template <class T> 116 class G4ThreadLocalSingleton; << 117 << 118 // this explicit specialization holds all the << 119 // to explicitly invoke the auto-deletion << 120 template <> << 121 class G4ThreadLocalSingleton<void> << 122 { << 123 private: << 124 using fvector_t = std::vector<std::function< << 125 << 126 template <class T> << 127 friend class G4ThreadLocalSingleton; << 128 << 129 static fvector_t& GetCallbacks(); << 130 static G4Mutex& GetMutex(); << 131 << 132 public: << 133 static void Clear(); << 134 << 135 template <typename FuncT> << 136 static typename fvector_t::iterator Insert(F << 137 { << 138 G4AutoLock _lk{ GetMutex() }; << 139 return GetCallbacks().emplace(GetCallbacks << 140 std::forward << 141 } << 142 }; << 143 << 144 template <class T> << 145 class G4ThreadLocalSingleton : private G4Cache 112 class G4ThreadLocalSingleton : private G4Cache<T*> 146 { 113 { 147 friend void G4AutoDelete::Register<T>(T*); 114 friend void G4AutoDelete::Register<T>(T*); 148 115 149 public: 116 public: 150 G4ThreadLocalSingleton(); 117 G4ThreadLocalSingleton(); 151 // Creates thread-local singleton manager 118 // Creates thread-local singleton manager 152 119 153 ~G4ThreadLocalSingleton() override; << 120 ~G4ThreadLocalSingleton(); 154 << 155 G4ThreadLocalSingleton(const G4ThreadLocalSi << 156 G4ThreadLocalSingleton(G4ThreadLocalSingleto << 157 << 158 G4ThreadLocalSingleton& operator=(const G4Th << 159 G4ThreadLocalSingleton& operator=(G4ThreadLo << 160 121 161 T* Instance() const; 122 T* Instance() const; 162 // Returns a pointer to a thread-private ins 123 // Returns a pointer to a thread-private instance of T 163 124 164 private: 125 private: >> 126 G4ThreadLocalSingleton(G4ThreadLocalSingleton& rhs); 165 void Register(T* i) const; 127 void Register(T* i) const; 166 128 167 void Clear(); 129 void Clear(); 168 130 169 mutable std::list<T*> instances; 131 mutable std::list<T*> instances; 170 mutable G4Mutex listm; 132 mutable G4Mutex listm; 171 }; 133 }; 172 134 173 //============================================ 135 //============================================================= 174 // Inline methods implementation 136 // Inline methods implementation 175 //============================================ 137 //============================================================= 176 138 177 template <class T> 139 template <class T> 178 G4ThreadLocalSingleton<T>::G4ThreadLocalSingle 140 G4ThreadLocalSingleton<T>::G4ThreadLocalSingleton() 179 : G4Cache<T*>() 141 : G4Cache<T*>() 180 { 142 { 181 G4MUTEXINIT(listm); 143 G4MUTEXINIT(listm); 182 G4Cache<T*>::Put(nullptr); << 144 G4Cache<T*>::Put(static_cast<T*>(0)); 183 // Uncomment below to find the origin of whe << 184 /* << 185 auto bt = G4Backtrace::GetDemangled<4, 1>( << 186 [](const char* cstr) { return std::string{ << 187 std::cout << "Backtrace to G4ThreadLocalSing << 188 << G4Demangle<T>().c_str() << ">:\ << 189 for(auto& itr : bt) << 190 { << 191 if(!itr.empty()) << 192 std::cout << "\t" << itr << "\n"; << 193 } << 194 */ << 195 G4ThreadLocalSingleton<void>::Insert([&]() { << 196 // printf("Deleting G4ThreadLocalSingleton << 197 // G4Demangle<T>().c_str()); << 198 this->Clear(); << 199 }); << 200 } 145 } 201 146 202 template <class T> 147 template <class T> 203 G4ThreadLocalSingleton<T>::~G4ThreadLocalSingl 148 G4ThreadLocalSingleton<T>::~G4ThreadLocalSingleton() 204 { 149 { 205 Clear(); 150 Clear(); 206 G4MUTEXDESTROY(listm); 151 G4MUTEXDESTROY(listm); 207 } 152 } 208 153 209 template <class T> 154 template <class T> 210 T* G4ThreadLocalSingleton<T>::Instance() const 155 T* G4ThreadLocalSingleton<T>::Instance() const 211 { 156 { 212 T* instance = G4Cache<T*>::Get(); 157 T* instance = G4Cache<T*>::Get(); 213 if(instance == static_cast<T*>(0)) 158 if(instance == static_cast<T*>(0)) 214 { 159 { 215 instance = new T; 160 instance = new T; 216 G4Cache<T*>::Put(instance); 161 G4Cache<T*>::Put(instance); 217 Register(instance); 162 Register(instance); 218 } 163 } 219 return instance; 164 return instance; 220 } 165 } 221 166 222 template <class T> 167 template <class T> >> 168 G4ThreadLocalSingleton<T>::G4ThreadLocalSingleton(G4ThreadLocalSingleton&) >> 169 {} >> 170 >> 171 template <class T> 223 void G4ThreadLocalSingleton<T>::Register(T* i) 172 void G4ThreadLocalSingleton<T>::Register(T* i) const 224 { 173 { 225 G4AutoLock l(&listm); 174 G4AutoLock l(&listm); 226 instances.push_back(i); 175 instances.push_back(i); 227 } 176 } 228 177 229 template <class T> 178 template <class T> 230 void G4ThreadLocalSingleton<T>::Clear() 179 void G4ThreadLocalSingleton<T>::Clear() 231 { 180 { 232 if(instances.empty()) << 233 return; << 234 G4AutoLock l(&listm); 181 G4AutoLock l(&listm); 235 while(!instances.empty()) 182 while(!instances.empty()) 236 { 183 { 237 T* thisinst = instances.front(); 184 T* thisinst = instances.front(); 238 instances.pop_front(); 185 instances.pop_front(); 239 delete thisinst; 186 delete thisinst; 240 } 187 } 241 } 188 } 242 189 243 #endif 190 #endif 244 191