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