Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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