Geant4-11
G4ThreadLocalSingleton.hh
Go to the documentation of this file.
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//
109namespace G4AutoDelete
110{
111 template <class T>
112 void Register(T*);
113}
114
115template <class T>
117
118// this explicit specialization holds all the callbacks
119// to explicitly invoke the auto-deletion
120template <>
122{
123 private:
124 using fvector_t = std::vector<std::function<void()>>;
125
126 template <class T>
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
144template <class T>
146{
147 friend void G4AutoDelete::Register<T>(T*);
148
149 public:
151 // Creates thread-local singleton manager
152
154
157
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
177template <class T>
179 : G4Cache<T*>()
180{
182 G4Cache<T*>::Put(static_cast<T*>(0));
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 */
196 printf("Deleting G4ThreadLocalSingletons for type %s ...\n",
197 G4Demangle<T>().c_str());
198 this->Clear();
199 });
200}
201
202template <class T>
204{
205 Clear();
206 G4MUTEXDESTROY(listm);
207}
208
209template <class T>
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
222template <class T>
224{
225 G4AutoLock l(&listm);
226 instances.push_back(i);
227}
228
229template <class T>
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
G4double(* function)(G4double)
#define G4MUTEXDESTROY(mutex)
Definition: G4Threading.hh:90
std::mutex G4Mutex
Definition: G4Threading.hh:81
#define G4MUTEXINIT(mutex)
Definition: G4Threading.hh:87
value_type & Get() const
Definition: G4Cache.hh:315
void Put(const value_type &val) const
Definition: G4Cache.hh:321
std::vector< std::function< void()> > fvector_t
static fvector_t::iterator Insert(FuncT &&_func)
G4ThreadLocalSingleton & operator=(G4ThreadLocalSingleton &&)=default
G4ThreadLocalSingleton(G4ThreadLocalSingleton &&)=default
G4ThreadLocalSingleton(const G4ThreadLocalSingleton &)=delete
G4ThreadLocalSingleton & operator=(const G4ThreadLocalSingleton &)=delete
void Register(T *inst)
Definition: G4AutoDelete.hh:65