Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/global/management/include/G4Cache.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // G4Cache
 27 //
 28 // Class Description:
 29 //
 30 //      Helper classes for Geant4 Multi-Threaded.
 31 //      The classes defined in this header file provide a thread-private
 32 //      cache to store a thread-local variable V in a class instance
 33 //      shared among threads.
 34 //      These are templated classes on the to-be-stored object.
 35 //
 36 // Example:
 37 //      Let's assume an instance myObject of class G4Shared is sharead between
 38 //      threads. Still a data member of this class needs to be thread-private.
 39 //      A typical example of this being a "cache" for a local calculation.
 40 //      The helper defined here can be used to guarantee thread-safe operations
 41 //      on the thread-private object.
 42 //      Example:
 43 //         class G4Shared
 44 //         {
 45 //           G4double sharedData;
 46 //           G4Cache<G4double> threadPrivate;
 47 //           void foo()
 48 //           {
 49 //             G4double priv = threadPrivate.Get();
 50 //             if ( priv < 10 ) priv += sharedData;
 51 //             threadPrivate.Put( priv );
 52 //           }
 53 //         }
 54 //
 55 //      Two variants of the base G4Cache exist. The first one being
 56 //      G4VectorCache similar to std::vector.
 57 //      Example:
 58 //         G4VectorCache<G4double> aVect;
 59 //         aVect.Push_back( 3.2 );
 60 //         aVect.Push_back( 4.1 );
 61 //         std::cout << aVect[0] << std::endl;
 62 //      The second one being:
 63 //      G4MapCache, similar to std::map.
 64 //      Example:
 65 //         G4MapCache<G4int, G4double> aMap;
 66 //         aMap[320]=1.234;
 67 //
 68 //      See classes definition for details.
 69 
 70 // Author: A.Dotti, 21 October 2013 - First implementation
 71 // --------------------------------------------------------------------
 72 #ifndef G4CACHE_HH
 73 #define G4CACHE_HH
 74 
 75 // Debug this code
 76 // #define g4cdebug 1
 77 
 78 #include <atomic>
 79 #include <map>
 80 #include <system_error>
 81 
 82 #include "G4AutoLock.hh"
 83 #include "G4CacheDetails.hh"  // Thread Local storage details are here
 84 
 85 // A templated cache to store a thread-private data of type VALTYPE.
 86 //
 87 template <class VALTYPE>
 88 class G4Cache
 89 {
 90  public:
 91   using value_type = VALTYPE;
 92   // The stored type
 93 
 94   G4Cache();
 95   // Default constructor
 96 
 97   G4Cache(const value_type& v);
 98   // Construct cache object with initial value
 99 
100   virtual ~G4Cache();
101   // Default destructor
102 
103   inline value_type& Get() const;
104   // Gets reference to cached value of this threads
105 
106   inline void Put(const value_type& val) const;
107   // Sets this thread cached value to val
108 
109   inline value_type Pop();
110   // Gets copy of cached value
111 
112   G4Cache(const G4Cache& rhs);
113   G4Cache& operator=(const G4Cache& rhs);
114 
115  protected:
116   const G4int& GetId() const { return id; }
117 
118  private:
119   G4int id;
120   mutable G4CacheReference<value_type> theCache;
121   static std::atomic<unsigned int> instancesctr;
122   static std::atomic<unsigned int> dstrctr;
123 
124   inline value_type& GetCache() const
125   {
126     theCache.Initialize(id);
127     return theCache.GetCache(id);
128   }
129 };
130 
131 // A vector version of the cache. Implements vector interface.
132 // Can be used directly as a std::vector would be used.
133 //
134 template <class VALTYPE>
135 class G4VectorCache : public G4Cache<std::vector<VALTYPE>>
136 {
137  public:
138   // Some useful definitions
139   //
140   using value_type = VALTYPE;
141   using vector_type = typename std::vector<value_type>;
142   using size_type = typename vector_type::size_type;
143   using iterator = typename vector_type::iterator;
144   using const_iterator = typename vector_type::const_iterator;
145 
146   G4VectorCache();
147   // Default constructor
148 
149   G4VectorCache(G4int nElems);
150   // Creates a vector cache of nElems elements
151 
152   G4VectorCache(G4int nElems, value_type* vals);
153   // Creates a vector cache with elements from an array
154 
155   virtual ~G4VectorCache();
156   // Default destructor
157 
158   // Interface with functionalities of similar name of std::vector
159   //
160   inline void Push_back(const value_type& val);
161   inline value_type Pop_back();
162   inline value_type& operator[](const G4int& idx);
163   inline iterator Begin();
164   inline iterator End();
165   inline void Clear();
166   inline size_type Size() { return G4Cache<vector_type>::Get().size(); }
167   //  Needs to be here for a VC9 compilation problem
168 };
169 
170 // a Map version of the cache. Implements std::map interface.
171 // Can be used directly as a std::map would be used.
172 // KEYTYPE being the key type and VALTYPE the value type.
173 //
174 template <class KEYTYPE, class VALTYPE>
175 class G4MapCache : public G4Cache<std::map<KEYTYPE, VALTYPE>>
176 {
177  public:
178   // Some useful definitions
179   //
180   using key_type = KEYTYPE;
181   using value_type = VALTYPE;
182   using map_type = typename std::map<key_type, value_type>;
183   using size_type = typename map_type::size_type;
184   using iterator = typename map_type::iterator;
185   using const_iterator = typename map_type::const_iterator;
186 
187   virtual ~G4MapCache();
188   // Default destructor
189 
190   inline G4bool Has(const key_type& k);
191   // Returns true if map contains element corresponding to key k
192 
193   // Interface with functionalities of similar name of std::map
194   //
195   inline std::pair<iterator, G4bool> Insert(const key_type& k,
196                                             const value_type& v);
197   inline iterator Begin();
198   inline iterator End();
199   inline iterator Find(const key_type& k);
200   inline value_type& Get(const key_type& k);
201   inline size_type Erase(const key_type& k);
202   inline value_type& operator[](const key_type& k);
203   inline size_type Size() { return G4Cache<map_type>::Get().size(); }
204   //  Needs to be here for a VC9 compilation problem
205 };
206 
207 //========= Implementation: G4Cache<V> ====================================
208 
209 template <class V>
210 G4Cache<V>::G4Cache()
211 {
212   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
213   id = instancesctr++;
214 #ifdef g4cdebug
215   std::cout << "G4Cache id: " << id << std::endl;
216 #endif
217 }
218 
219 template <class V>
220 G4Cache<V>::G4Cache(const G4Cache<V>& rhs)
221 {
222   // Copy is special, we need to copy the content
223   // of the cache, not the cache object
224 
225   if(this == &rhs)
226     return;
227   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
228   id = instancesctr++;
229 
230   // Force copy of cached data
231   //
232   V aCopy = rhs.GetCache();
233   Put(aCopy);
234 
235 #ifdef g4cdebug
236   std::cout << "Copy constructor with id: " << id << std::endl;
237 #endif
238 }
239 
240 template <class V>
241 G4Cache<V>& G4Cache<V>::operator=(const G4Cache<V>& rhs)
242 {
243   if(this == &rhs)
244     return *this;
245 
246   // Force copy of cached data
247   //
248   V aCopy = rhs.GetCache();
249   Put(aCopy);
250 
251 #ifdef g4cdebug
252   std::cout << "Assignement operator with id: " << id << std::endl;
253 #endif
254   return *this;
255 }
256 
257 template <class V>
258 G4Cache<V>::G4Cache(const V& v)
259 {
260   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
261   id = instancesctr++;
262   Put(v);
263 
264 #ifdef g4cdebug
265   std::cout << "G4Cache id: " << id << std::endl;
266 #endif
267 }
268 
269 template <class V>
270 G4Cache<V>::~G4Cache()
271 {
272 #ifdef g4cdebug
273   std::cout << "~G4Cache id: " << id << std::endl;
274 #endif
275   // don't automatically lock --> wait until we can catch an error
276   // without scoping the G4AutoLock
277   //
278   G4AutoLock l(G4TypeMutex<G4Cache<V>>(), std::defer_lock);
279 
280   // sometimes the mutex is unavailable in destructors so
281   // try to lock the associated mutex, but catch if it fails
282   try
283   {
284     // a system_error in lock means that the mutex is unavailable
285     // we want to throw the error that comes from locking an unavailable
286     // mutex so that we know there is a memory leak
287     // if the mutex is valid, this will hold until the other thread finishes
288     //
289     l.lock();
290   } catch(std::system_error& e)
291   {
292     // the error that comes from locking an unavailable mutex
293 #ifdef G4VERBOSE
294     G4cout << "Non-critical error: mutex lock failure in ~G4Cache<"
295            << typeid(V).name() << ">. " << G4endl
296            << "If the RunManagerKernel has been deleted, it failed to "
297            << "delete an allocated resource" << G4endl
298            << "and this destructor is being called after the statics "
299            << "were destroyed." << G4endl;
300     G4cout << "Exception: [code: " << e.code() << "] caught: " << e.what()
301            << G4endl;
302 #endif
303   }
304   ++dstrctr;
305   G4bool last = (dstrctr == instancesctr);
306   theCache.Destroy(id, last);
307   if(last)
308   {
309     instancesctr.store(0);
310     dstrctr.store(0);
311   }
312 }
313 
314 template <class V>
315 V& G4Cache<V>::Get() const
316 {
317   return GetCache();
318 }
319 
320 template <class V>
321 void G4Cache<V>::Put(const V& val) const
322 {
323   GetCache() = val;
324 }
325 
326 // Should here remove from cache element?
327 template <class V>
328 V G4Cache<V>::Pop()
329 {
330   return GetCache();
331 }
332 
333 template <class V>
334 std::atomic<unsigned int> G4Cache<V>::instancesctr(0);
335 
336 template <class V>
337 std::atomic<unsigned int> G4Cache<V>::dstrctr(0);
338 
339 //========== Implementation: G4VectorCache<V> ===========================
340 
341 template <class V>
342 G4VectorCache<V>::G4VectorCache() = default;
343 
344 template <class V>
345 G4VectorCache<V>::~G4VectorCache()
346 {
347 #ifdef g4cdebug
348   std::cout << "~G4VectorCache "
349             << G4Cache<G4VectorCache<V>::vector_type>::GetId()
350             << " with size: " << Size() << "->";
351   for(size_type i = 0; i < Size(); ++i)
352     std::cout << operator[](i) << ",";
353   std::cout << "<-" << std::endl;
354 #endif
355 }
356 
357 template <class V>
358 G4VectorCache<V>::G4VectorCache(G4int nElems)
359 {
360   vector_type& cc = G4Cache<vector_type>::Get();
361   cc.resize(nElems);
362 }
363 
364 template <class V>
365 G4VectorCache<V>::G4VectorCache(G4int nElems, V* vals)
366 {
367   vector_type& cc = G4Cache<vector_type>::Get();
368   cc.resize(nElems);
369   for(G4int idx = 0; idx < nElems; ++idx)
370     cc[idx] = vals[idx];
371 }
372 
373 template <class V>
374 void G4VectorCache<V>::Push_back(const V& val)
375 {
376   G4Cache<vector_type>::Get().push_back(val);
377 }
378 
379 template <class V>
380 V G4VectorCache<V>::Pop_back()
381 {
382   vector_type& cc = G4Cache<vector_type>::Get();
383   value_type val  = cc[cc.size() - 1];
384   cc.pop_back();
385   return val;
386 }
387 
388 template <class V>
389 V& G4VectorCache<V>::operator[](const G4int& idx)
390 {
391   vector_type& cc = G4Cache<vector_type>::Get();
392   return cc[idx];
393 }
394 
395 template <class V>
396 typename G4VectorCache<V>::iterator G4VectorCache<V>::Begin()
397 {
398   return G4Cache<vector_type>::Get().begin();
399 }
400 
401 template <class V>
402 typename G4VectorCache<V>::iterator G4VectorCache<V>::End()
403 {
404   return G4Cache<vector_type>::Get().end();
405 }
406 
407 template <class V>
408 void G4VectorCache<V>::Clear()
409 {
410   G4Cache<vector_type>::Get().clear();
411 }
412 
413 // template<class V>
414 // typename G4VectorCache<V>::size_type G4VectorCache<V>::Size()
415 //{
416 //    return G4Cache<vector_type>::Get().size();
417 //}
418 
419 //======== Implementation: G4MapType<K,V> ===========================
420 
421 template <class K, class V>
422 G4MapCache<K, V>::~G4MapCache()
423 {
424 #ifdef g4cdebug
425   std::cout << "~G4MacCache " << G4Cache<map_type>::GetId()
426             << " with size: " << Size() << "->";
427   for(iterator it = Begin(); it != End(); ++it)
428     std::cout << it->first << ":" << it->second << ",";
429   std::cout << "<-" << std::endl;
430 #endif
431 }
432 
433 template <class K, class V>
434 std::pair<typename G4MapCache<K, V>::iterator, G4bool> G4MapCache<K, V>::Insert(
435   const K& k, const V& v)
436 {
437   return G4Cache<map_type>::Get().insert(std::pair<key_type, value_type>(k, v));
438 }
439 
440 // template<class K, class V>
441 // typename G4MapCache<K,V>::size_type G4MapCache<K,V>::Size()
442 //{
443 //    return G4Cache<map_type>::Get().size();
444 //}
445 
446 template <class K, class V>
447 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::Begin()
448 {
449   return G4Cache<map_type>::Get().begin();
450 }
451 template <class K, class V>
452 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::End()
453 {
454   return G4Cache<map_type>::Get().end();
455 }
456 
457 template <class K, class V>
458 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::Find(const K& k)
459 {
460   return G4Cache<map_type>::Get().find(k);
461 }
462 
463 template <class K, class V>
464 G4bool G4MapCache<K, V>::Has(const K& k)
465 {
466   return (Find(k) != End());
467 }
468 
469 template <class K, class V>
470 V& G4MapCache<K, V>::Get(const K& k)
471 {
472   return Find(k)->second;
473 }
474 
475 template <class K, class V>
476 typename G4MapCache<K, V>::size_type G4MapCache<K, V>::Erase(const K& k)
477 {
478   return G4Cache<map_type>::Get().erase(k);
479 }
480 
481 template <class K, class V>
482 V& G4MapCache<K, V>::operator[](const K& k)
483 {
484   return (G4Cache<map_type>::Get())[k];
485 }
486 
487 #endif
488