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