Geant4 11.2.2
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 "G4AutoLock.hh"
56#include "globals.hh"
57
58#include "rundefs.hh"
59#include <stdlib.h>
60
61template<class T> // T is the private data from the object to be split
63{
64 public:
66
67 // Invoked by the master thread to create a new subinstance
68 // whenever a new split class instance is created.
69 // This is called by constructor of shared classes,
70 // thus only master thread calls this
72 {
73 G4AutoLock l(&mutex);
74 // One more instance
75 ++totalobj;
76 // If the number of objects is larger than the available spaces,
77 // a re-allocation is needed
78 if (totalobj > workertotalspace) {
79 l.unlock();
81 l.lock();
82 }
83 // Since this is called by Master thread, we can remember this
84 totalspace = workertotalspace;
85 sharedOffset = offset;
86 return (totalobj - 1);
87 }
88
89 // Invoked by each worker thread to grow the subinstance array and
90 // initialize each new subinstance using a particular method defined
91 // by the subclass.
93 {
94 G4AutoLock l(&mutex);
95 if (workertotalspace >= totalobj) {
96 return;
97 }
98 // Remember current large size
99 G4int originaltotalspace = workertotalspace;
100 // Increase its size by some value (purely arbitrary)
101 workertotalspace = totalobj + 512;
102 // Now re-allocate new space
103 offset = (T*)realloc(offset, workertotalspace * sizeof(T));
104 if (offset == nullptr) {
105 G4Exception("G4VUPLSplitter::NewSubInstances()", "OutOfMemory", FatalException,
106 "Cannot malloc space!");
107 return;
108 }
109 // The newly created objects need to be initialized
110 for (G4int i = originaltotalspace; i < workertotalspace; ++i) {
111 offset[i].initialize();
112 }
113 }
114
115 // Invoked by all threads to free the subinstance array.
117 {
118 if (offset == nullptr) {
119 return;
120 }
121 free(offset);
122 offset = nullptr;
123 }
124
125 T* GetOffset() { return offset; }
126
127 void UseWorkArea(T* newOffset)
128 {
129 // Use recycled work area - which was created previously
130 if (offset != nullptr && offset != newOffset) {
131 G4Exception("G4VUPLSplitter::UseWorkspace()", "TwoWorkspaces", FatalException,
132 "Thread already has workspace - cannot use another.");
133 }
134 offset = newOffset;
135 }
136
138 {
139 // Detach this thread from this Location
140 // The object which calls this method is responsible for it.
141 //
142 T* offsetRet = offset;
143 offset = nullptr;
144
145 return offsetRet;
146 }
147
148 // Invoked by each worker thread to copy all subinstances array from
149 // the master thread
151 {
152 if (offset != nullptr) return;
153
154 // Since this is called by worker threds, totalspace is some valid
155 // number > 0. Remember totalspace is the number of available slots
156 // from master. We are sure that it has valid data
157 G4AutoLock l(&mutex);
158 offset = (T*)realloc(offset, totalspace * sizeof(T));
159 if (offset == nullptr) {
160 G4Exception("G4VUPLSplitter::WorkerCopySubInstanceArray()", "OutOfMemory", FatalException,
161 "Cannot malloc space!");
162 return;
163 }
164 // Now just copy from master thread (sharedOffset)
165 std::memcpy(offset, sharedOffset, totalspace * sizeof(T));
166 }
167
168 public:
169 // Per-thread available number of slots
171 // Pointer to first instance of an array
173
174 private:
175 G4int totalobj = 0; // Total number of instances from master thread
176 G4int totalspace = 0; // Available number of "slots"
177 T* sharedOffset = nullptr;
179};
180
181template<typename T>
183template<typename T>
185
186#endif
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::mutex G4Mutex
#define G4MUTEXINIT(mutex)
int G4int
Definition G4Types.hh:85
void WorkerCopySubInstanceArray()
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