ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4VUPLSplitter.hh
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4VUPLSplitter.hh
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 //
27 //
28 //
29 // ------------------------------------------------------------
30 //
31 // GEANT 4 class header file
32 //
33 // ---------------- G4UPLSplitter ----------------
34 //
35 // Utility template class for splitting RW data for thread-safety from
36 // classes: G4UserPhysicsList, G4VPhysicsConstructor and G4CModularPhsyicsList
37 //
38 // ------------------------------------------------------------
39 // History:
40 // 01.25.2009 Xin Dong: First implementation from automatic MT conversion.
41 // ------------------------------------------------------------
42 #ifndef G4VUPLSPLITTER_HH
43 #define G4VUPLSPLITTER_HH
44 
45 #include <stdlib.h>
46 
47 #include "globals.hh"
48 #include "rundefs.hh"
49 #include "G4AutoLock.hh"
50 //
51 // This class implements the split-mechanism for shared objects.
52 // Let's see how it works.
53 // In the split-class we have an instance of this class and an G4int instanceID
54 // Every time, in the master thread a new instance of the split-class
55 // is created the constructor calls:
56 // instanceID = g4vuplsplitter.CreateInstance();
57 // This creates in memory an "array", pointed by "sharedOffset" of capacity "totalspace"
58 // The array contains "totalobj" (<=totalspace) instances (i.e. the array has
59 // un-initialized spaces)
60 // Note that also the TLS variables "offset" and "workertotalspace" have also the same stuff
61 // When a worker thread is started we can call g4vuplsplitter.NewSubInstances()
62 // This will simply allocate enough space in the TLS space "offset" and call
63 // T::initialize() onto the new created methods.
64 // Alternatively one can call, when the worker thread start, g4vuplsplitter.workerCopySubInstanceArray()
65 // That will copy the content of master thread "array" into the TLS one
66 
67 // To see this stuff in action see:
68 // G4VUserPhysicsList class and G4WorkerThread classes.
69 
70 template <class T> // T is the private data from the object to be split
72 {
73  public:
74 
76  {
78  }
79 
81  // Invoked by the master thread to create a new subinstance
82  // whenever a new split class instance is created.
83  // This is called by constructor of shared classes, thus only master thread
84  // calls this
85  {
86  G4AutoLock l(&mutex);
87  //One more instance
88  totalobj++;
89  //If the number of objects is larger than the available spaces,
90  //a re-allocation is needed
92  {
93  l.unlock();
95  l.lock();
96  }
97  //Since this is called by Master thread, we can remember this
100  return (totalobj - 1);
101  }
102 
104  // Invoked by each worker thread to grow the subinstance array and
105  // initialize each new subinstance using a particular method defined
106  // by the subclass.
107  {
108  G4AutoLock l(&mutex);
109  if (workertotalspace >= totalobj) { return; }
110  //Remember current large size
111  G4int originaltotalspace = workertotalspace;
112  //Increase its size by some value (purely arbitrary)
113  workertotalspace = totalobj + 512;
114  //Now re-allocate new space
115  offset = (T *) realloc(offset, workertotalspace * sizeof(T));
116  if (offset == 0)
117  {
118  G4Exception("G4VUPLSplitter::NewSubInstances()",
119  "OutOfMemory", FatalException, "Cannot malloc space!");
120  return;
121  }
122  //The newly created objects need to be initialized
123  for (G4int i = originaltotalspace; i < workertotalspace; i++)
124  {
125  offset[i].initialize();
126  }
127  }
128 
129  void FreeWorker()
130  // Invoked by all threads to free the subinstance array.
131  {
132  if (!offset) { return; }
133  free( offset);
134  offset = 0;
135  }
136 
137  T* GetOffset() { return offset; }
138 
139  void UseWorkArea( T* newOffset )
140  {
141  // Use recycled work area - which was created previously
142  if( offset && offset!=newOffset )
143  {
144  G4Exception("G4VUPLSplitter::UseWorkspace()",
145  "TwoWorkspaces", FatalException,
146  "Thread already has workspace - cannot use another.");
147  }
148  offset= newOffset;
149  // totalobj= numObjects;
150  // totalspace= numSpace;
151  }
152 
153  T* FreeWorkArea() // G4int* numObjects, G4int* numSpace)
154  {
155  // Detach this thread from this Location
156  // The object which calls this method is responsible for it.
157  //
158  T* offsetRet= offset;
159 
160  offset= 0;
161 
162  return offsetRet;
163  }
164 
166  //Invoked by each worker thread to copy all subinstances array from
167  //the master thread
168  {
169  if ( offset ) return;
170  //Since this is called by worker threds, totalspace is some valid number > 0
171  //Remember totalspace is the number of availabel slots from master.
172  //We are sure that it has valid data
173  G4AutoLock l(&mutex);
174  offset = (T *)realloc(offset,totalspace * sizeof(T));
175  if (offset == 0)
176  {
177  G4Exception("G4VUPLSplitter::WorkerCopySubInstanceArray()",
178  "OutOfMemory", FatalException, "Cannot malloc space!");
179  return;
180  }
181  //Now just copy from master thread (sharedOffset)
182  memcpy(offset,sharedOffset,totalspace*sizeof(T));
183  }
184  public:
185 
186  G4RUN_DLL G4ThreadLocalStatic G4int workertotalspace; //Per-thread available number of slots
187  G4RUN_DLL G4ThreadLocalStatic T* offset; //Pointer to first instance of an array
188 
189  private:
190  G4int totalobj; //Total number of instances from master thread
191  G4int totalspace; // Available number of "slots"
194 };
195 
197 template<typename T> G4ThreadLocal T* G4VUPLSplitter<T>::offset=0;
198 
199 #endif