Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:59:11

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4ThreadLocalSingleton
0027 //
0028 // Class description:
0029 //
0030 // This class implements a thread-private "singleton". Being thread
0031 // private the singleton is not a singleton in the term, but a different
0032 // instance exists for each thread.
0033 // This class is a wrapper around the real object that we need to
0034 // make singleton.
0035 //
0036 // Limitation:
0037 //   The object that is made thread-private singleton should not
0038 //   contain any thread-local data member. Note that in general,
0039 //   if an object is to be thread-private it is unnecessary to mark
0040 //   any data-member as G4ThreadLocal.
0041 //
0042 // Performance issues:
0043 //   This class uses locks and mutexes.
0044 //
0045 // Example:
0046 //   This is the singleton pattern often found in Geant4 (sequential):
0047 //   class G4Class
0048 //   {
0049 //     private:
0050 //       static G4Class* instance;
0051 //        G4Class() { ... }
0052 //     public:
0053 //       static G4Class* GetInstance()
0054 //       {
0055 //         static G4Class theInstance;
0056 //         if ( instance == nullptr ) instance = &theInstance;
0057 //         return instance;
0058 //       }
0059 //   };
0060 //   This is transformed to the following to implement a thread-local
0061 //   singleton:
0062 //   class G4Class
0063 //   {
0064 //     private:
0065 //       static G4ThreadLocal G4Class* instance;
0066 //       G4Class() { ... }
0067 //     public:
0068 //       static G4Class* GetInstance()
0069 //       {
0070 //         if ( instance == nullptr ) instance = new G4Class;
0071 //           return instance;
0072 //       }
0073 //   };
0074 //   Note that this class also has a memory leak.
0075 //
0076 //   This class can be used as follows:
0077 //   class G4Class
0078 //   {
0079 //     friend class G4ThreadLocalSingleton<G4Class>;
0080 //     private:
0081 //       G4Class() { ... }
0082 //     public:
0083 //       static G4Class* GetInstance()
0084 //       {
0085 //         static G4ThreadLocalSingleton<G4Class> instance;
0086 //         return instance.Instance();
0087 //       }
0088 //   };
0089 //   Each thread has its own instance of G4Class.
0090 //   Deletion of G4Class instances is done at end of program.
0091 //   Note the "friend" statement.
0092 
0093 // Author: A.Dotti, 28 October 2013
0094 // --------------------------------------------------------------------
0095 #ifndef G4TLSSINGLETON_HH
0096 #define G4TLSSINGLETON_HH 1
0097 
0098 #include "G4AutoLock.hh"
0099 #include "G4Cache.hh"
0100 #include "G4Backtrace.hh"
0101 #include "G4Threading.hh"
0102 
0103 #include <list>
0104 #include <vector>
0105 #include <functional>
0106 
0107 // Forward declaration. See G4AutoDelete.hh
0108 //
0109 namespace G4AutoDelete
0110 {
0111   template <class T>
0112   void Register(T*);
0113 }
0114 
0115 template <class T>
0116 class G4ThreadLocalSingleton;
0117 
0118 // this explicit specialization holds all the callbacks
0119 // to explicitly invoke the auto-deletion
0120 template <>
0121 class G4ThreadLocalSingleton<void>
0122 {
0123  private:
0124   using fvector_t = std::vector<std::function<void()>>;
0125 
0126   template <class T>
0127   friend class G4ThreadLocalSingleton;
0128 
0129   static fvector_t& GetCallbacks();
0130   static G4Mutex& GetMutex();
0131 
0132  public:
0133   static void Clear();
0134 
0135   template <typename FuncT>
0136   static typename fvector_t::iterator Insert(FuncT&& _func)
0137   {
0138     G4AutoLock _lk{ GetMutex() };
0139     return GetCallbacks().emplace(GetCallbacks().end(),
0140                                   std::forward<FuncT>(_func));
0141   }
0142 };
0143 
0144 template <class T>
0145 class G4ThreadLocalSingleton : private G4Cache<T*>
0146 {
0147   friend void G4AutoDelete::Register<T>(T*);
0148 
0149  public:
0150   G4ThreadLocalSingleton();
0151   // Creates thread-local singleton manager
0152 
0153   ~G4ThreadLocalSingleton() override;
0154 
0155   G4ThreadLocalSingleton(const G4ThreadLocalSingleton&) = delete;
0156   G4ThreadLocalSingleton(G4ThreadLocalSingleton&&)      = default;
0157 
0158   G4ThreadLocalSingleton& operator=(const G4ThreadLocalSingleton&) = delete;
0159   G4ThreadLocalSingleton& operator=(G4ThreadLocalSingleton&&) = default;
0160 
0161   T* Instance() const;
0162   // Returns a pointer to a thread-private instance of T
0163 
0164  private:
0165   void Register(T* i) const;
0166 
0167   void Clear();
0168 
0169   mutable std::list<T*> instances;
0170   mutable G4Mutex listm;
0171 };
0172 
0173 //=============================================================
0174 // Inline methods implementation
0175 //=============================================================
0176 
0177 template <class T>
0178 G4ThreadLocalSingleton<T>::G4ThreadLocalSingleton()
0179   : G4Cache<T*>()
0180 {
0181   G4MUTEXINIT(listm);
0182   G4Cache<T*>::Put(nullptr);
0183   // Uncomment below to find the origin of where instantiation happened
0184   /*
0185   auto bt = G4Backtrace::GetDemangled<4, 1>(
0186     [](const char* cstr) { return std::string{ cstr }; });
0187   std::cout << "Backtrace to G4ThreadLocalSingleton<"
0188             << G4Demangle<T>().c_str() << ">:\n";
0189   for(auto& itr : bt)
0190   {
0191     if(!itr.empty())
0192       std::cout << "\t" << itr << "\n";
0193   }
0194   */
0195   G4ThreadLocalSingleton<void>::Insert([&]() {
0196     // printf("Deleting G4ThreadLocalSingletons for type %s ...\n",
0197     //       G4Demangle<T>().c_str());
0198     this->Clear();
0199   });
0200 }
0201 
0202 template <class T>
0203 G4ThreadLocalSingleton<T>::~G4ThreadLocalSingleton()
0204 {
0205   Clear();
0206   G4MUTEXDESTROY(listm);
0207 }
0208 
0209 template <class T>
0210 T* G4ThreadLocalSingleton<T>::Instance() const
0211 {
0212   T* instance = G4Cache<T*>::Get();
0213   if(instance == static_cast<T*>(0))
0214   {
0215     instance = new T;
0216     G4Cache<T*>::Put(instance);
0217     Register(instance);
0218   }
0219   return instance;
0220 }
0221 
0222 template <class T>
0223 void G4ThreadLocalSingleton<T>::Register(T* i) const
0224 {
0225   G4AutoLock l(&listm);
0226   instances.push_back(i);
0227 }
0228 
0229 template <class T>
0230 void G4ThreadLocalSingleton<T>::Clear()
0231 {
0232   if(instances.empty())
0233     return;
0234   G4AutoLock l(&listm);
0235   while(!instances.empty())
0236   {
0237     T* thisinst = instances.front();
0238     instances.pop_front();
0239     delete thisinst;
0240   }
0241 }
0242 
0243 #endif