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 "G4AutoLock.hh" 98 #include "G4AutoLock.hh" 99 #include "G4Cache.hh" 99 #include "G4Cache.hh" 100 #include "G4Backtrace.hh" 100 #include "G4Backtrace.hh" 101 #include "G4Threading.hh" 101 #include "G4Threading.hh" 102 102 103 #include <list> 103 #include <list> 104 #include <vector> 104 #include <vector> 105 #include <functional> 105 #include <functional> 106 106 107 // Forward declaration. See G4AutoDelete.hh 107 // Forward declaration. See G4AutoDelete.hh 108 // 108 // 109 namespace G4AutoDelete 109 namespace G4AutoDelete 110 { 110 { 111 template <class T> 111 template <class T> 112 void Register(T*); 112 void Register(T*); 113 } 113 } 114 114 115 template <class T> 115 template <class T> 116 class G4ThreadLocalSingleton; 116 class G4ThreadLocalSingleton; 117 117 118 // this explicit specialization holds all the 118 // this explicit specialization holds all the callbacks 119 // to explicitly invoke the auto-deletion 119 // to explicitly invoke the auto-deletion 120 template <> 120 template <> 121 class G4ThreadLocalSingleton<void> 121 class G4ThreadLocalSingleton<void> 122 { 122 { 123 private: 123 private: 124 using fvector_t = std::vector<std::function< 124 using fvector_t = std::vector<std::function<void()>>; 125 125 126 template <class T> 126 template <class T> 127 friend class G4ThreadLocalSingleton; 127 friend class G4ThreadLocalSingleton; 128 128 129 static fvector_t& GetCallbacks(); 129 static fvector_t& GetCallbacks(); 130 static G4Mutex& GetMutex(); 130 static G4Mutex& GetMutex(); 131 131 132 public: 132 public: 133 static void Clear(); 133 static void Clear(); 134 134 135 template <typename FuncT> 135 template <typename FuncT> 136 static typename fvector_t::iterator Insert(F 136 static typename fvector_t::iterator Insert(FuncT&& _func) 137 { 137 { 138 G4AutoLock _lk{ GetMutex() }; 138 G4AutoLock _lk{ GetMutex() }; 139 return GetCallbacks().emplace(GetCallbacks 139 return GetCallbacks().emplace(GetCallbacks().end(), 140 std::forward 140 std::forward<FuncT>(_func)); 141 } 141 } 142 }; 142 }; 143 143 144 template <class T> 144 template <class T> 145 class G4ThreadLocalSingleton : private G4Cache 145 class G4ThreadLocalSingleton : private G4Cache<T*> 146 { 146 { 147 friend void G4AutoDelete::Register<T>(T*); 147 friend void G4AutoDelete::Register<T>(T*); 148 148 149 public: 149 public: 150 G4ThreadLocalSingleton(); 150 G4ThreadLocalSingleton(); 151 // Creates thread-local singleton manager 151 // Creates thread-local singleton manager 152 152 153 ~G4ThreadLocalSingleton() override; 153 ~G4ThreadLocalSingleton() override; 154 154 155 G4ThreadLocalSingleton(const G4ThreadLocalSi 155 G4ThreadLocalSingleton(const G4ThreadLocalSingleton&) = delete; 156 G4ThreadLocalSingleton(G4ThreadLocalSingleto 156 G4ThreadLocalSingleton(G4ThreadLocalSingleton&&) = default; 157 157 158 G4ThreadLocalSingleton& operator=(const G4Th 158 G4ThreadLocalSingleton& operator=(const G4ThreadLocalSingleton&) = delete; 159 G4ThreadLocalSingleton& operator=(G4ThreadLo 159 G4ThreadLocalSingleton& operator=(G4ThreadLocalSingleton&&) = default; 160 160 161 T* Instance() const; 161 T* Instance() const; 162 // Returns a pointer to a thread-private ins 162 // Returns a pointer to a thread-private instance of T 163 163 164 private: 164 private: 165 void Register(T* i) const; 165 void Register(T* i) const; 166 166 167 void Clear(); 167 void Clear(); 168 168 169 mutable std::list<T*> instances; 169 mutable std::list<T*> instances; 170 mutable G4Mutex listm; 170 mutable G4Mutex listm; 171 }; 171 }; 172 172 173 //============================================ 173 //============================================================= 174 // Inline methods implementation 174 // Inline methods implementation 175 //============================================ 175 //============================================================= 176 176 177 template <class T> 177 template <class T> 178 G4ThreadLocalSingleton<T>::G4ThreadLocalSingle 178 G4ThreadLocalSingleton<T>::G4ThreadLocalSingleton() 179 : G4Cache<T*>() 179 : G4Cache<T*>() 180 { 180 { 181 G4MUTEXINIT(listm); 181 G4MUTEXINIT(listm); 182 G4Cache<T*>::Put(nullptr); 182 G4Cache<T*>::Put(nullptr); 183 // Uncomment below to find the origin of whe 183 // Uncomment below to find the origin of where instantiation happened 184 /* 184 /* 185 auto bt = G4Backtrace::GetDemangled<4, 1>( 185 auto bt = G4Backtrace::GetDemangled<4, 1>( 186 [](const char* cstr) { return std::string{ 186 [](const char* cstr) { return std::string{ cstr }; }); 187 std::cout << "Backtrace to G4ThreadLocalSing 187 std::cout << "Backtrace to G4ThreadLocalSingleton<" 188 << G4Demangle<T>().c_str() << ">:\ 188 << G4Demangle<T>().c_str() << ">:\n"; 189 for(auto& itr : bt) 189 for(auto& itr : bt) 190 { 190 { 191 if(!itr.empty()) 191 if(!itr.empty()) 192 std::cout << "\t" << itr << "\n"; 192 std::cout << "\t" << itr << "\n"; 193 } 193 } 194 */ 194 */ 195 G4ThreadLocalSingleton<void>::Insert([&]() { 195 G4ThreadLocalSingleton<void>::Insert([&]() { 196 // printf("Deleting G4ThreadLocalSingleton 196 // printf("Deleting G4ThreadLocalSingletons for type %s ...\n", 197 // G4Demangle<T>().c_str()); 197 // G4Demangle<T>().c_str()); 198 this->Clear(); 198 this->Clear(); 199 }); 199 }); 200 } 200 } 201 201 202 template <class T> 202 template <class T> 203 G4ThreadLocalSingleton<T>::~G4ThreadLocalSingl 203 G4ThreadLocalSingleton<T>::~G4ThreadLocalSingleton() 204 { 204 { 205 Clear(); 205 Clear(); 206 G4MUTEXDESTROY(listm); 206 G4MUTEXDESTROY(listm); 207 } 207 } 208 208 209 template <class T> 209 template <class T> 210 T* G4ThreadLocalSingleton<T>::Instance() const 210 T* G4ThreadLocalSingleton<T>::Instance() const 211 { 211 { 212 T* instance = G4Cache<T*>::Get(); 212 T* instance = G4Cache<T*>::Get(); 213 if(instance == static_cast<T*>(0)) 213 if(instance == static_cast<T*>(0)) 214 { 214 { 215 instance = new T; 215 instance = new T; 216 G4Cache<T*>::Put(instance); 216 G4Cache<T*>::Put(instance); 217 Register(instance); 217 Register(instance); 218 } 218 } 219 return instance; 219 return instance; 220 } 220 } 221 221 222 template <class T> 222 template <class T> 223 void G4ThreadLocalSingleton<T>::Register(T* i) 223 void G4ThreadLocalSingleton<T>::Register(T* i) const 224 { 224 { 225 G4AutoLock l(&listm); 225 G4AutoLock l(&listm); 226 instances.push_back(i); 226 instances.push_back(i); 227 } 227 } 228 228 229 template <class T> 229 template <class T> 230 void G4ThreadLocalSingleton<T>::Clear() 230 void G4ThreadLocalSingleton<T>::Clear() 231 { 231 { 232 if(instances.empty()) 232 if(instances.empty()) 233 return; 233 return; 234 G4AutoLock l(&listm); 234 G4AutoLock l(&listm); 235 while(!instances.empty()) 235 while(!instances.empty()) 236 { 236 { 237 T* thisinst = instances.front(); 237 T* thisinst = instances.front(); 238 instances.pop_front(); 238 instances.pop_front(); 239 delete thisinst; 239 delete thisinst; 240 } 240 } 241 } 241 } 242 242 243 #endif 243 #endif 244 244