|
||||
File indexing completed on 2025-01-18 09:59:28
0001 // 0002 // ******************************************************************** 0003 // * License and Disclaimer * 0004 // * * 0005 // * The Geant4 software is copyright of the Copyright Holders of * 0006 // * the Geant4 Collaboration. It is provided under the terms and * 0007 // * conditions of the Geant4 Software License, included in the file * 0008 // * LICENSE and available at http://cern.ch/geant4/license . These * 0009 // * include a list of copyright holders. * 0010 // * * 0011 // * Neither the authors of this software system, nor their employing * 0012 // * institutes,nor the agencies providing financial support for this * 0013 // * work make any representation or warranty, express or implied, * 0014 // * regarding this software system or assume any liability for its * 0015 // * use. Please see the license in the file LICENSE and URL above * 0016 // * for the full disclaimer and the limitation of liability. * 0017 // * * 0018 // * This code implementation is the result of the scientific and * 0019 // * technical work of the GEANT4 collaboration. * 0020 // * By using, copying, modifying or distributing the software (or * 0021 // * any work based on the software) you agree to acknowledge its * 0022 // * use in resulting scientific publications, and indicate your * 0023 // * acceptance of all terms of the Geant4 Software license. * 0024 // ******************************************************************** 0025 // 0026 // G4VUPLSplitter 0027 // 0028 // Class description: 0029 // 0030 // Utility template class for splitting RW data for thread-safety from classes: 0031 // G4UserPhysicsList, G4VPhysicsConstructor and G4VModularPhysicsList. 0032 // This class implements the split-mechanism for shared objects. 0033 // In the split-class we have an instance of this class and an 'instanceID'. 0034 // Every time in the master thread a new instance of the split-class is 0035 // created, the constructor calls: 0036 // instanceID = g4vuplsplitter.CreateInstance(); 0037 // This creates in memory an "array", pointed by "sharedOffset" of capacity 0038 // "totalspace". The array contains "totalobj" (<=totalspace) instances 0039 // (i.e. the array has un-initialized spaces). Note that also the TLS variables 0040 // "offset" and "workertotalspace" have also the same stuff. When a worker 0041 // thread is started we can call g4vuplsplitter.NewSubInstances(). This will 0042 // simply allocate enough space in the TLS space "offset" and call 0043 // T::initialize() onto the new created methods. Alternatively one can call, 0044 // when the worker thread start, g4vuplsplitter.workerCopySubInstanceArray(), 0045 // that will copy the content of master thread "array" into the TLS one. 0046 // To see this stuff in action see the G4VUserPhysicsList and G4WorkerThread 0047 // classes. 0048 0049 // Author: Xin Dong, 25 January 2009 - First implementation from 0050 // automatic MT conversion. 0051 // -------------------------------------------------------------------- 0052 #ifndef G4VUPLSplitter_hh 0053 #define G4VUPLSplitter_hh 1 0054 0055 #include "G4AutoLock.hh" 0056 #include "globals.hh" 0057 0058 #include "rundefs.hh" 0059 #include <stdlib.h> 0060 0061 template<class T> // T is the private data from the object to be split 0062 class G4VUPLSplitter 0063 { 0064 public: 0065 G4VUPLSplitter() { G4MUTEXINIT(mutex); } 0066 0067 // Invoked by the master thread to create a new subinstance 0068 // whenever a new split class instance is created. 0069 // This is called by constructor of shared classes, 0070 // thus only master thread calls this 0071 G4int CreateSubInstance() 0072 { 0073 G4AutoLock l(&mutex); 0074 // One more instance 0075 ++totalobj; 0076 // If the number of objects is larger than the available spaces, 0077 // a re-allocation is needed 0078 if (totalobj > workertotalspace) { 0079 l.unlock(); 0080 NewSubInstances(); 0081 l.lock(); 0082 } 0083 // Since this is called by Master thread, we can remember this 0084 totalspace = workertotalspace; 0085 sharedOffset = offset; 0086 return (totalobj - 1); 0087 } 0088 0089 // Invoked by each worker thread to grow the subinstance array and 0090 // initialize each new subinstance using a particular method defined 0091 // by the subclass. 0092 void NewSubInstances() 0093 { 0094 G4AutoLock l(&mutex); 0095 if (workertotalspace >= totalobj) { 0096 return; 0097 } 0098 // Remember current large size 0099 G4int originaltotalspace = workertotalspace; 0100 // Increase its size by some value (purely arbitrary) 0101 workertotalspace = totalobj + 512; 0102 // Now re-allocate new space 0103 offset = (T*)realloc(offset, workertotalspace * sizeof(T)); 0104 if (offset == nullptr) { 0105 G4Exception("G4VUPLSplitter::NewSubInstances()", "OutOfMemory", FatalException, 0106 "Cannot malloc space!"); 0107 return; 0108 } 0109 // The newly created objects need to be initialized 0110 for (G4int i = originaltotalspace; i < workertotalspace; ++i) { 0111 offset[i].initialize(); 0112 } 0113 } 0114 0115 // Invoked by all threads to free the subinstance array. 0116 void FreeWorker() 0117 { 0118 if (offset == nullptr) { 0119 return; 0120 } 0121 free(offset); 0122 offset = nullptr; 0123 } 0124 0125 T* GetOffset() { return offset; } 0126 0127 void UseWorkArea(T* newOffset) 0128 { 0129 // Use recycled work area - which was created previously 0130 if (offset != nullptr && offset != newOffset) { 0131 G4Exception("G4VUPLSplitter::UseWorkspace()", "TwoWorkspaces", FatalException, 0132 "Thread already has workspace - cannot use another."); 0133 } 0134 offset = newOffset; 0135 } 0136 0137 T* FreeWorkArea() 0138 { 0139 // Detach this thread from this Location 0140 // The object which calls this method is responsible for it. 0141 // 0142 T* offsetRet = offset; 0143 offset = nullptr; 0144 0145 return offsetRet; 0146 } 0147 0148 // Invoked by each worker thread to copy all subinstances array from 0149 // the master thread 0150 void WorkerCopySubInstanceArray() 0151 { 0152 if (offset != nullptr) return; 0153 0154 // Since this is called by worker threds, totalspace is some valid 0155 // number > 0. Remember totalspace is the number of available slots 0156 // from master. We are sure that it has valid data 0157 G4AutoLock l(&mutex); 0158 offset = (T*)realloc(offset, totalspace * sizeof(T)); 0159 if (offset == nullptr) { 0160 G4Exception("G4VUPLSplitter::WorkerCopySubInstanceArray()", "OutOfMemory", FatalException, 0161 "Cannot malloc space!"); 0162 return; 0163 } 0164 // Now just copy from master thread (sharedOffset) 0165 std::memcpy(offset, sharedOffset, totalspace * sizeof(T)); 0166 } 0167 0168 public: 0169 // Per-thread available number of slots 0170 G4RUN_DLL G4ThreadLocalStatic G4int workertotalspace; 0171 // Pointer to first instance of an array 0172 G4RUN_DLL G4ThreadLocalStatic T* offset; 0173 0174 private: 0175 G4int totalobj = 0; // Total number of instances from master thread 0176 G4int totalspace = 0; // Available number of "slots" 0177 T* sharedOffset = nullptr; 0178 G4Mutex mutex; 0179 }; 0180 0181 template<typename T> 0182 G4ThreadLocal G4int G4VUPLSplitter<T>::workertotalspace = 0; 0183 template<typename T> 0184 G4ThreadLocal T* G4VUPLSplitter<T>::offset = nullptr; 0185 0186 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |