Geant4 Cross Reference |
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 // G4MTRunManagerKernel implementation 27 // 28 // Author: M.Asai - July 2013 29 // -------------------------------------------------------------------- 30 #include "G4MTRunManagerKernel.hh" 31 32 #include "G4AutoLock.hh" 33 #include "G4DecayTable.hh" 34 #include "G4LogicalVolume.hh" 35 #include "G4Material.hh" 36 #include "G4MaterialTable.hh" 37 #include "G4PVParameterised.hh" 38 #include "G4PVReplica.hh" 39 #include "G4ParticleDefinition.hh" 40 #include "G4ParticleTable.hh" 41 #include "G4ParticleTableIterator.hh" 42 #include "G4PhysicalVolumeStore.hh" 43 #include "G4PhysicsVector.hh" 44 #include "G4PolyconeSide.hh" 45 #include "G4PolyhedraSide.hh" 46 #include "G4Region.hh" 47 #include "G4RegionStore.hh" 48 #include "G4StateManager.hh" 49 #include "G4UImanager.hh" 50 #include "G4UserWorkerInitialization.hh" 51 #include "G4UserWorkerThreadInitialization.hh" 52 #include "G4VDecayChannel.hh" 53 #include "G4VModularPhysicsList.hh" 54 #include "G4VPhysicalVolume.hh" 55 #include "G4VPhysicsConstructor.hh" 56 #include "G4VUserActionInitialization.hh" 57 #include "G4VUserPhysicsList.hh" 58 #include "G4WorkerRunManager.hh" 59 #include "G4WorkerThread.hh" 60 61 std::vector<G4WorkerRunManager*>* G4MTRunManagerKernel::workerRMvector = nullptr; 62 63 G4ThreadLocal G4WorkerThread* G4MTRunManagerKernel::wThreadContext = nullptr; 64 65 // -------------------------------------------------------------------- 66 namespace 67 { 68 G4Mutex workerRMMutex = G4MUTEX_INITIALIZER; 69 } 70 71 // -------------------------------------------------------------------- 72 G4MTRunManagerKernel::G4MTRunManagerKernel() : G4RunManagerKernel(masterRMK) 73 { 74 // This version of the constructor should never be called in sequential mode! 75 #ifndef G4MULTITHREADED 76 G4ExceptionDescription msg; 77 msg << "Geant4 code is compiled without multi-threading support " 78 "(-DG4MULTITHREADED " 79 "is set to off)."; 80 msg << " This type of RunManager can only be used in mult-threaded " 81 "applications."; 82 G4Exception("G4RunManagerKernel::G4RunManagerKernel()", "Run0109", FatalException, msg); 83 #endif 84 G4AutoLock l(&workerRMMutex); 85 if (workerRMvector == nullptr) workerRMvector = new std::vector<G4WorkerRunManager*>; 86 l.unlock(); 87 // Set flag that a MT-type kernel has been instantiated 88 G4Threading::SetMultithreadedApplication(true); 89 } 90 91 // -------------------------------------------------------------------- 92 G4MTRunManagerKernel::~G4MTRunManagerKernel() 93 { 94 G4AutoLock l(&workerRMMutex); 95 if (workerRMvector != nullptr) { 96 if (!workerRMvector->empty()) { 97 G4ExceptionDescription msg; 98 msg << "G4MTRunManagerKernel is to be deleted while " << workerRMvector->size() 99 << " G4WorkerRunManager are still alive."; 100 G4Exception("G4RunManagerKernel::~G4RunManagerKernel()", "Run10035", FatalException, msg); 101 } 102 delete workerRMvector; 103 workerRMvector = nullptr; 104 } 105 } 106 107 // -------------------------------------------------------------------- 108 void G4MTRunManagerKernel::SetupShadowProcess() const 109 { 110 // Behavior is the same as base class (sequential mode) 111 // ShadowProcess pointer == process poitner 112 G4RunManagerKernel::SetupShadowProcess(); 113 } 114 115 // -------------------------------------------------------------------- 116 G4WorkerThread* G4MTRunManagerKernel::GetWorkerThread() 117 { 118 return wThreadContext; 119 } 120 121 // -------------------------------------------------------------------- 122 void G4MTRunManagerKernel::StartThread(G4WorkerThread* context) 123 { 124 //!!!!!!!!!!!!!!!!!!!!!!!!!! 125 //!!!!!! IMPORTANT !!!!!!!!! 126 //!!!!!!!!!!!!!!!!!!!!!!!!!! 127 // Here is not sequential anymore and G4UserWorkerThreadInitialization is 128 // a shared user initialization class. 129 // This means this method cannot use data members of G4RunManagerKernel 130 // unless they are invariant ("read-only") and can be safely shared. 131 // All the rest that is not invariant should be incapsulated into 132 // the context (or, as for wThreadContext be G4ThreadLocal) 133 //!!!!!!!!!!!!!!!!!!!!!!!!!! 134 // #ifdef G4MULTITHREADED 135 // turnontpmalloc(); 136 // #endif 137 G4Threading::WorkerThreadJoinsPool(); 138 wThreadContext = context; 139 G4MTRunManager* masterRM = G4MTRunManager::GetMasterRunManager(); 140 141 //============================ 142 // Step-0: Thread ID 143 //============================ 144 // Initialise per-thread stream-output 145 // The following line is needed before we actually do IO initialisation 146 // because the constructor of UI manager resets the IO destination. 147 G4int thisID = wThreadContext->GetThreadId(); 148 G4Threading::G4SetThreadId(thisID); 149 G4UImanager::GetUIpointer()->SetUpForAThread(thisID); 150 151 //============================ 152 // Optimization: optional 153 //============================ 154 // Enforce thread affinity if requested 155 wThreadContext->SetPinAffinity(masterRM->GetPinAffinity()); 156 157 //============================ 158 // Step-1: Random number engine 159 //============================ 160 // RNG Engine needs to be initialised by "cloning" the master one. 161 const CLHEP::HepRandomEngine* masterEngine = masterRM->getMasterRandomEngine(); 162 masterRM->GetUserWorkerThreadInitialization()->SetupRNGEngine(masterEngine); 163 164 //============================ 165 // Step-2: Initialise worker thread 166 //============================ 167 if (masterRM->GetUserWorkerInitialization() != nullptr) { 168 masterRM->GetUserWorkerInitialization()->WorkerInitialize(); 169 } 170 if (masterRM->GetUserActionInitialization() != nullptr) { 171 G4VSteppingVerbose* sv = masterRM->GetUserActionInitialization()->InitializeSteppingVerbose(); 172 if (sv != nullptr) { 173 G4VSteppingVerbose::SetInstance(sv); 174 } 175 } 176 // Now initialise worker part of shared objects (geometry/physics) 177 G4WorkerThread::BuildGeometryAndPhysicsVector(); 178 G4WorkerRunManager* wrm = masterRM->GetUserWorkerThreadInitialization()->CreateWorkerRunManager(); 179 wrm->SetWorkerThread(wThreadContext); 180 G4AutoLock wrmm(&workerRMMutex); 181 workerRMvector->push_back(wrm); 182 wrmm.unlock(); 183 184 //================================ 185 // Step-3: Setup worker run manager 186 //================================ 187 // Set the detector and physics list to the worker thread. Share with master 188 const G4VUserDetectorConstruction* detector = masterRM->GetUserDetectorConstruction(); 189 wrm->G4RunManager::SetUserInitialization(const_cast<G4VUserDetectorConstruction*>(detector)); 190 const G4VUserPhysicsList* physicslist = masterRM->GetUserPhysicsList(); 191 wrm->SetUserInitialization(const_cast<G4VUserPhysicsList*>(physicslist)); 192 193 //================================ 194 // Step-4: Initialise worker run manager 195 //================================ 196 if (masterRM->GetUserActionInitialization() != nullptr) { 197 masterRM->GetNonConstUserActionInitialization()->Build(); 198 } 199 if (masterRM->GetUserWorkerInitialization() != nullptr) { 200 masterRM->GetUserWorkerInitialization()->WorkerStart(); 201 } 202 wrm->Initialize(); 203 204 //================================ 205 // Step5: Loop over requests from the master thread 206 //================================ 207 // This function should enter a loop processing new runs and actions 208 // requests from master. It should block until thread is ready 209 // to terminate 210 wrm->DoWork(); 211 212 //=============================== 213 // Step-6: Terminate worker thread 214 //=============================== 215 if (masterRM->GetUserWorkerInitialization() != nullptr) { 216 masterRM->GetUserWorkerInitialization()->WorkerStop(); 217 } 218 219 wrmm.lock(); 220 for (auto itrWrm = workerRMvector->cbegin(); itrWrm != workerRMvector->cend(); ++itrWrm) { 221 if ((*itrWrm) == wrm) { 222 workerRMvector->erase(itrWrm); 223 break; 224 } 225 } 226 wrmm.unlock(); 227 delete wrm; 228 229 //=============================== 230 // Step-7: Cleanup split classes 231 //=============================== 232 G4WorkerThread::DestroyGeometryAndPhysicsVector(); 233 wThreadContext = nullptr; 234 235 G4Threading::WorkerThreadLeavesPool(); 236 } 237 238 // -------------------------------------------------------------------- 239 void G4MTRunManagerKernel::SetUpDecayChannels() 240 { 241 auto pItr = G4ParticleTable::GetParticleTable()->GetIterator(); 242 pItr->reset(); 243 while ((*pItr)()) { 244 G4DecayTable* dt = pItr->value()->GetDecayTable(); 245 if (dt != nullptr) { 246 G4int nCh = dt->entries(); 247 for (G4int i = 0; i < nCh; ++i) { 248 dt->GetDecayChannel(i)->GetDaughter(0); 249 } 250 } 251 } 252 } 253 254 // -------------------------------------------------------------------- 255 void G4MTRunManagerKernel::BroadcastAbortRun(G4bool softAbort) 256 { 257 G4AutoLock wrmm(&workerRMMutex); 258 259 for (const auto& itr : *workerRMvector) { 260 itr->AbortRun(softAbort); 261 } 262 } 263