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 // G4MTRunManager implementation 27 // 28 // Original authors: X.Dong, A.Dotti - February 2013 29 // -------------------------------------------------------------------- 30 31 #include "G4MTRunManager.hh" 32 33 #include "G4AutoLock.hh" 34 #include "G4CopyRandomState.hh" 35 #include "G4MTRunManagerKernel.hh" 36 #include "G4ProductionCutsTable.hh" 37 #include "G4Run.hh" 38 #include "G4ScoringManager.hh" 39 #include "G4StateManager.hh" 40 #include "G4Timer.hh" 41 #include "G4TransportationManager.hh" 42 #include "G4UImanager.hh" 43 #include "G4UserRunAction.hh" 44 #include "G4UserWorkerInitialization.hh" 45 #include "G4UserWorkerThreadInitialization.hh" 46 #include "G4VUserActionInitialization.hh" 47 #include "G4WorkerRunManager.hh" 48 #include "G4WorkerThread.hh" 49 50 G4ScoringManager* G4MTRunManager::masterScM = nullptr; 51 G4MTRunManager* G4MTRunManager::fMasterRM = nullptr; 52 G4int G4MTRunManager::seedOncePerCommunication = 0; 53 G4ThreadId G4MTRunManager::masterThreadId = G4ThisThread::get_id(); 54 55 // -------------------------------------------------------------------- 56 namespace 57 { 58 G4Mutex cmdHandlingMutex = G4MUTEX_INITIALIZER; 59 G4Mutex scorerMergerMutex = G4MUTEX_INITIALIZER; 60 G4Mutex runMergerMutex = G4MUTEX_INITIALIZER; 61 G4Mutex setUpEventMutex = G4MUTEX_INITIALIZER; 62 } // namespace 63 64 // -------------------------------------------------------------------- 65 G4MTRunManager* G4MTRunManager::GetMasterRunManager() 66 { 67 return fMasterRM; 68 } 69 70 // -------------------------------------------------------------------- 71 G4RunManagerKernel* G4MTRunManager::GetMasterRunManagerKernel() 72 { 73 return fMasterRM->kernel; 74 } 75 76 // -------------------------------------------------------------------- 77 G4MTRunManagerKernel* G4MTRunManager::GetMTMasterRunManagerKernel() 78 { 79 return fMasterRM->MTkernel; 80 } 81 82 // -------------------------------------------------------------------- 83 G4ScoringManager* G4MTRunManager::GetMasterScoringManager() 84 { 85 return masterScM; 86 } 87 88 // -------------------------------------------------------------------- 89 G4MTRunManager::masterWorlds_t& G4MTRunManager::GetMasterWorlds() 90 { 91 static masterWorlds_t masterWorlds; 92 return masterWorlds; 93 } 94 95 // -------------------------------------------------------------------- 96 void G4MTRunManager::addWorld(G4int counter, G4VPhysicalVolume* w) 97 { 98 GetMasterWorlds().insert(std::make_pair(counter, w)); 99 } 100 101 // -------------------------------------------------------------------- 102 G4ThreadId G4MTRunManager::GetMasterThreadId() 103 { 104 return masterThreadId; 105 } 106 107 // -------------------------------------------------------------------- 108 G4int G4MTRunManager::SeedOncePerCommunication() 109 { 110 return seedOncePerCommunication; 111 } 112 113 // -------------------------------------------------------------------- 114 void G4MTRunManager::SetSeedOncePerCommunication(G4int val) 115 { 116 seedOncePerCommunication = val; 117 } 118 119 // -------------------------------------------------------------------- 120 G4MTRunManager::G4MTRunManager() : G4RunManager(masterRM) 121 { 122 if (fMasterRM != nullptr) { 123 G4Exception("G4MTRunManager::G4MTRunManager", "Run0110", FatalException, 124 "Another instance of a G4MTRunManager already exists."); 125 } 126 fMasterRM = this; 127 masterThreadId = G4ThisThread::get_id(); 128 MTkernel = static_cast<G4MTRunManagerKernel*>(kernel); 129 #ifndef G4MULTITHREADED 130 G4ExceptionDescription msg; 131 msg << "Geant4 code is compiled without multi-threading support" 132 << "(-DG4MULTITHREADED is set to off).\n"; 133 msg << "G4MTRunManager can only be used in multi-threaded applications."; 134 G4Exception("G4MTRunManager::G4MTRunManager", "Run0111", FatalException, msg); 135 #endif 136 137 G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators(); 138 if (numberOfStaticAllocators > 0) { 139 G4ExceptionDescription msg1; 140 msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n" 141 << "In multi-threaded mode, all G4Allocator objects must be dynamically " 142 "instantiated."; 143 G4Exception("G4MTRunManager::G4MTRunManager", "Run1035", FatalException, msg1); 144 } 145 G4UImanager::GetUIpointer()->SetMasterUIManager(true); 146 masterScM = G4ScoringManager::GetScoringManagerIfExist(); 147 148 // Check if a default RandomNumberGenerator has been created by user, 149 // if not create default one 150 // Note this call forces creation of defaults if not already there 151 // G4Random::getTheEngine(); //User did not specify RNG, create defaults 152 // Now remember the master instance of the RNG Engine 153 masterRNGEngine = G4Random::getTheEngine(); 154 155 randDbl = new G4double[nSeedsPerEvent * nSeedsMax]; 156 157 char* env = std::getenv("G4FORCENUMBEROFTHREADS"); 158 if (env != nullptr) { 159 G4String envS = env; 160 if (envS == "MAX" || envS == "max") { 161 forcedNwokers = G4Threading::G4GetNumberOfCores(); 162 } 163 else { 164 std::istringstream is(env); 165 G4int val = -1; 166 is >> val; 167 if (val > 0) { 168 forcedNwokers = val; 169 } 170 else { 171 G4ExceptionDescription msg2; 172 msg2 << "Environment variable G4FORCENUMBEROFTHREADS has an invalid " 173 "value <" 174 << envS << ">. It has to be an integer or a word \"max\".\n" 175 << "G4FORCENUMBEROFTHREADS is ignored."; 176 G4Exception("G4MTRunManager::G4MTRunManager", "Run1039", JustWarning, msg2); 177 } 178 } 179 if (forcedNwokers > 0) { 180 nworkers = forcedNwokers; 181 if (verboseLevel > 0) { 182 G4cout << "### Number of threads is forced to " << forcedNwokers 183 << " by Environment variable G4FORCENUMBEROFTHREADS." << G4endl; 184 } 185 } 186 } 187 G4UImanager::GetUIpointer()->SetAlias("RunMode eventParallel"); 188 } 189 190 // -------------------------------------------------------------------- 191 G4MTRunManager::~G4MTRunManager() 192 { 193 // TODO: Currently does not work due to concurrent deletion of something 194 // that is shared: 195 // G4ProcessTable::DeleteMessenger from ~G4RunManager 196 // G4cout<<"Destroy MTRunManager"<<G4endl;//ANDREA 197 TerminateWorkers(); 198 delete[] randDbl; 199 } 200 201 // -------------------------------------------------------------------- 202 void G4MTRunManager::StoreRNGStatus(const G4String& fn) 203 { 204 std::ostringstream os; 205 os << randomNumberStatusDir << "G4Master_" << fn << ".rndm"; 206 G4Random::saveEngineStatus(os.str().c_str()); 207 } 208 209 // -------------------------------------------------------------------- 210 void G4MTRunManager::rndmSaveThisRun() 211 { 212 G4int runNumber = 0; 213 if (currentRun != nullptr) runNumber = currentRun->GetRunID(); 214 if (!storeRandomNumberStatus) { 215 G4cerr << "Warning from G4RunManager::rndmSaveThisRun():" 216 << " Random number status was not stored prior to this run." << G4endl 217 << "/random/setSavingFlag command must be issued. " 218 << "Command ignored." << G4endl; 219 return; 220 } 221 222 G4fs::path fileIn = randomNumberStatusDir + "G4Worker_currentRun.rndm"; 223 224 std::ostringstream os; 225 os << "run" << runNumber << ".rndm" << '\0'; 226 G4fs::path fileOut = randomNumberStatusDir + os.str(); 227 228 if (G4CopyRandomState(fileIn, fileOut, "G4MTRunManager::rndmSaveThisRun()") && verboseLevel > 0) 229 { 230 G4cout << fileIn << " is copied to " << fileOut << G4endl; 231 } 232 } 233 234 // -------------------------------------------------------------------- 235 void G4MTRunManager::rndmSaveThisEvent() 236 { 237 G4Exception("G4MTRunManager::rndmSaveThisEvent", "RUN_RNDM001", FatalException, 238 "This method shall not be invoked !!"); 239 } 240 241 // -------------------------------------------------------------------- 242 void G4MTRunManager::SetNumberOfThreads(G4int n) 243 { 244 if (!threads.empty()) { 245 G4ExceptionDescription msg; 246 msg << "Number of threads cannot be changed at this moment \n" 247 << "(old threads are still alive). Method ignored."; 248 G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)", "Run0112", JustWarning, msg); 249 } 250 else if (forcedNwokers > 0) { 251 G4ExceptionDescription msg; 252 msg << "Number of threads is forced to " << forcedNwokers 253 << " by G4FORCENUMBEROFTHREADS shell variable.\n" 254 << "Method ignored."; 255 G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)", "Run0113", JustWarning, msg); 256 } 257 else { 258 nworkers = n; 259 } 260 } 261 262 // -------------------------------------------------------------------- 263 void G4MTRunManager::Initialize() 264 { 265 G4RunManager::Initialize(); 266 267 // make sure all worker threads are set up. 268 BeamOn(0); 269 SetRunIDCounter(0); 270 } 271 272 // -------------------------------------------------------------------- 273 void G4MTRunManager::ProcessOneEvent(G4int) 274 { 275 // Nothing to do 276 } 277 278 // -------------------------------------------------------------------- 279 void G4MTRunManager::TerminateOneEvent() 280 { 281 // Nothing to do 282 } 283 284 // -------------------------------------------------------------------- 285 void G4MTRunManager::PrepareCommandsStack() 286 { 287 G4AutoLock l(&cmdHandlingMutex); 288 uiCmdsForWorkers.clear(); 289 std::vector<G4String>* cmdCopy = G4UImanager::GetUIpointer()->GetCommandStack(); 290 for (const auto& it : *cmdCopy) 291 uiCmdsForWorkers.push_back(it); 292 cmdCopy->clear(); 293 delete cmdCopy; 294 } 295 296 // -------------------------------------------------------------------- 297 std::vector<G4String> G4MTRunManager::GetCommandStack() 298 { 299 G4AutoLock l(&cmdHandlingMutex); 300 return uiCmdsForWorkers; 301 } 302 303 // -------------------------------------------------------------------- 304 void G4MTRunManager::CreateAndStartWorkers() 305 { 306 // Now loop on requested number of workers 307 // This will also start the workers 308 // Currently we do not allow to change the 309 // number of threads: threads area created once 310 if (threads.empty()) { 311 if (verboseLevel > 0) { 312 // for consistency with G4TaskRunManager 313 std::stringstream msg; 314 msg << "--> G4MTRunManager::CreateAndStartWorkers() --> " 315 << "Initializing workers..."; 316 317 std::stringstream ss; 318 ss.fill('='); 319 ss << std::setw(G4int(msg.str().length())) << ""; 320 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl; 321 } 322 323 for (G4int nw = 0; nw < nworkers; ++nw) { 324 // Create a new worker and remember it 325 auto context = new G4WorkerThread; 326 context->SetNumberThreads(nworkers); 327 context->SetThreadId(nw); 328 G4Thread* thread = userWorkerThreadInitialization->CreateAndStartWorker(context); 329 threads.push_back(thread); 330 } 331 } 332 // Signal to threads they can start a new run 333 NewActionRequest(WorkerActionRequest::NEXTITERATION); 334 } 335 336 // -------------------------------------------------------------------- 337 void G4MTRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select) 338 { 339 MTkernel->SetUpDecayChannels(); 340 numberOfEventToBeProcessed = n_event; 341 numberOfEventProcessed = 0; 342 343 if (!fakeRun) { 344 nSeedsUsed = 0; 345 nSeedsFilled = 0; 346 347 if (verboseLevel > 0) { 348 timer->Start(); 349 } 350 351 n_select_msg = n_select; 352 if (macroFile != nullptr) { 353 if (n_select_msg < 0) n_select_msg = n_event; 354 msgText = "/control/execute "; 355 msgText += macroFile; 356 selectMacro = macroFile; 357 } 358 else { 359 n_select_msg = -1; 360 selectMacro = ""; 361 } 362 363 // initialize seeds 364 // If user did not implement InitializeSeeds, 365 // use default: nSeedsPerEvent seeds per event 366 if (eventModuloDef > 0) { 367 eventModulo = eventModuloDef; 368 if (eventModulo > numberOfEventToBeProcessed / nworkers) { 369 eventModulo = numberOfEventToBeProcessed / nworkers; 370 if (eventModulo < 1) eventModulo = 1; 371 G4ExceptionDescription msgd; 372 msgd << "Event modulo is reduced to " << eventModulo 373 << " to distribute events to all threads."; 374 G4Exception("G4MTRunManager::InitializeEventLoop()", "Run10035", JustWarning, msgd); 375 } 376 } 377 else { 378 eventModulo = G4int(std::sqrt(G4double(numberOfEventToBeProcessed / nworkers))); 379 if (eventModulo < 1) eventModulo = 1; 380 } 381 if (!InitializeSeeds(n_event) && n_event > 0) { 382 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 383 switch (seedOncePerCommunication) { 384 case 0: 385 nSeedsFilled = n_event; 386 break; 387 case 1: 388 nSeedsFilled = nworkers; 389 break; 390 case 2: 391 nSeedsFilled = n_event / eventModulo + 1; 392 break; 393 default: 394 G4ExceptionDescription msgd; 395 msgd << "Parameter value <" << seedOncePerCommunication 396 << "> of seedOncePerCommunication is invalid. It is reset to 0."; 397 G4Exception("G4MTRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd); 398 seedOncePerCommunication = 0; 399 nSeedsFilled = n_event; 400 } 401 402 // Generates up to nSeedsMax seed pairs only. 403 if (nSeedsFilled > nSeedsMax) nSeedsFilled = nSeedsMax; 404 masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl); 405 helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent); 406 } 407 } 408 409 // Now initialize workers. Check if user defined a WorkerThreadInitialization 410 if (userWorkerThreadInitialization == nullptr) { 411 userWorkerThreadInitialization = new G4UserWorkerThreadInitialization(); 412 } 413 414 // Prepare UI commands for threads 415 PrepareCommandsStack(); 416 417 // Start worker threads 418 CreateAndStartWorkers(); 419 420 // We need a barrier here. Wait for workers to start event loop. 421 // This will return only when all workers have started processing events. 422 WaitForReadyWorkers(); 423 } 424 425 // -------------------------------------------------------------------- 426 void G4MTRunManager::RefillSeeds() 427 { 428 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 429 G4int nFill = 0; 430 switch (seedOncePerCommunication) { 431 case 0: 432 nFill = numberOfEventToBeProcessed - nSeedsFilled; 433 break; 434 case 1: 435 nFill = nworkers - nSeedsFilled; 436 break; 437 case 2: 438 default: 439 nFill = (numberOfEventToBeProcessed - nSeedsFilled * eventModulo) / eventModulo + 1; 440 } 441 // Generates up to nSeedsMax seed pairs only. 442 if (nFill > nSeedsMax) nFill = nSeedsMax; 443 masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl); 444 helper->Refill(randDbl, nFill); 445 nSeedsFilled += nFill; 446 } 447 448 // -------------------------------------------------------------------- 449 void G4MTRunManager::RunTermination() 450 { 451 // Wait for all worker threads to have finished the run 452 // i.e. wait for them to return from RunTermination() 453 // This guarantee that userrunaction for workers has been called 454 455 // Wait now for all threads to finish event-loop 456 WaitForEndEventLoopWorkers(); 457 // Now call base-class methof 458 G4RunManager::TerminateEventLoop(); 459 G4RunManager::RunTermination(); 460 } 461 462 // -------------------------------------------------------------------- 463 void G4MTRunManager::ConstructScoringWorlds() 464 { 465 masterScM = G4ScoringManager::GetScoringManagerIfExist(); 466 // Call base class stuff... 467 G4RunManager::ConstructScoringWorlds(); 468 469 GetMasterWorlds().clear(); 470 auto nWorlds = (G4int)G4TransportationManager::GetTransportationManager()->GetNoWorlds(); 471 auto itrW = G4TransportationManager::GetTransportationManager()->GetWorldsIterator(); 472 for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) { 473 addWorld(iWorld, *itrW); 474 ++itrW; 475 } 476 } 477 478 // -------------------------------------------------------------------- 479 void G4MTRunManager::SetUserInitialization(G4UserWorkerInitialization* userInit) 480 { 481 userWorkerInitialization = userInit; 482 } 483 484 // -------------------------------------------------------------------- 485 void G4MTRunManager::SetUserInitialization(G4UserWorkerThreadInitialization* userInit) 486 { 487 userWorkerThreadInitialization = userInit; 488 } 489 490 // -------------------------------------------------------------------- 491 void G4MTRunManager::SetUserInitialization(G4VUserActionInitialization* userInit) 492 { 493 userActionInitialization = userInit; 494 userActionInitialization->BuildForMaster(); 495 } 496 497 // -------------------------------------------------------------------- 498 void G4MTRunManager::SetUserInitialization(G4VUserPhysicsList* userPL) 499 { 500 G4RunManager::SetUserInitialization(userPL); 501 // Needed for MT, to be moved in kernel 502 } 503 504 // -------------------------------------------------------------------- 505 void G4MTRunManager::SetUserInitialization(G4VUserDetectorConstruction* userDC) 506 { 507 G4RunManager::SetUserInitialization(userDC); 508 } 509 510 // -------------------------------------------------------------------- 511 void G4MTRunManager::SetUserAction(G4UserRunAction* userAction) 512 { 513 G4RunManager::SetUserAction(userAction); 514 if (userAction != nullptr) userAction->SetMaster(); 515 } 516 517 // -------------------------------------------------------------------- 518 void G4MTRunManager::SetUserAction(G4VUserPrimaryGeneratorAction* /*userAction*/) 519 { 520 G4Exception("G4MTRunManager::SetUserAction()", "Run0123", FatalException, 521 "For multi-threaded version, define G4VUserPrimaryGeneratorAction in " 522 "G4VUserActionInitialization."); 523 } 524 525 // -------------------------------------------------------------------- 526 void G4MTRunManager::SetUserAction(G4UserEventAction* /*userAction*/) 527 { 528 G4Exception("G4MTRunManager::SetUserAction()", "Run0124", FatalException, 529 "For multi-threaded version, define G4UserEventAction in " 530 "G4VUserActionInitialization."); 531 } 532 533 // -------------------------------------------------------------------- 534 void G4MTRunManager::SetUserAction(G4UserStackingAction* /*userAction*/) 535 { 536 G4Exception("G4MTRunManager::SetUserAction()", "Run0125", FatalException, 537 "For multi-threaded version, define G4UserStackingAction in " 538 "G4VUserActionInitialization."); 539 } 540 541 // -------------------------------------------------------------------- 542 void G4MTRunManager::SetUserAction(G4UserTrackingAction* /*userAction*/) 543 { 544 G4Exception("G4MTRunManager::SetUserAction()", "Run0126", FatalException, 545 "For multi-threaded version, define G4UserTrackingAction in " 546 "G4VUserActionInitialization."); 547 } 548 549 // -------------------------------------------------------------------- 550 void G4MTRunManager::SetUserAction(G4UserSteppingAction* /*userAction*/) 551 { 552 G4Exception("G4MTRunManager::SetUserAction()", "Run0127", FatalException, 553 "For multi-threaded version, define G4UserSteppingAction in " 554 "G4VUserActionInitialization."); 555 } 556 557 // -------------------------------------------------------------------- 558 void G4MTRunManager::MergeScores(const G4ScoringManager* localScoringManager) 559 { 560 G4AutoLock l(&scorerMergerMutex); 561 if (masterScM != nullptr && localScoringManager != nullptr) masterScM->Merge(localScoringManager); 562 } 563 564 // -------------------------------------------------------------------- 565 void G4MTRunManager::MergeRun(const G4Run* localRun) 566 { 567 G4AutoLock l(&runMergerMutex); 568 if (currentRun != nullptr && localRun != nullptr) currentRun->Merge(localRun); 569 } 570 571 // -------------------------------------------------------------------- 572 G4bool G4MTRunManager::SetUpAnEvent(G4Event* evt, G4long& s1, G4long& s2, G4long& s3, 573 G4bool reseedRequired) 574 { 575 G4AutoLock l(&setUpEventMutex); 576 if (numberOfEventProcessed < numberOfEventToBeProcessed) { 577 evt->SetEventID(numberOfEventProcessed); 578 if (reseedRequired) { 579 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 580 G4int idx_rndm = nSeedsPerEvent * nSeedsUsed; 581 s1 = helper->GetSeed(idx_rndm); 582 s2 = helper->GetSeed(idx_rndm + 1); 583 if (nSeedsPerEvent == 3) s3 = helper->GetSeed(idx_rndm + 2); 584 ++nSeedsUsed; 585 if (nSeedsUsed == nSeedsFilled) RefillSeeds(); 586 } 587 ++numberOfEventProcessed; 588 return true; 589 } 590 return false; 591 } 592 593 // -------------------------------------------------------------------- 594 G4int G4MTRunManager::SetUpNEvents(G4Event* evt, G4SeedsQueue* seedsQueue, G4bool reseedRequired) 595 { 596 G4AutoLock l(&setUpEventMutex); 597 if (numberOfEventProcessed < numberOfEventToBeProcessed && !runAborted) { 598 G4int nev = eventModulo; 599 if (numberOfEventProcessed + nev > numberOfEventToBeProcessed) { 600 nev = numberOfEventToBeProcessed - numberOfEventProcessed; 601 } 602 evt->SetEventID(numberOfEventProcessed); 603 if (reseedRequired) { 604 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 605 G4int nevRnd = nev; 606 if (seedOncePerCommunication > 0) nevRnd = 1; 607 for (G4int i = 0; i < nevRnd; ++i) { 608 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed)); 609 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1)); 610 if (nSeedsPerEvent == 3) seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2)); 611 ++nSeedsUsed; 612 if (nSeedsUsed == nSeedsFilled) RefillSeeds(); 613 } 614 } 615 numberOfEventProcessed += nev; 616 return nev; 617 } 618 return 0; 619 } 620 621 // -------------------------------------------------------------------- 622 void G4MTRunManager::TerminateWorkers() 623 { 624 // Force workers to execute (if any) all UI commands left in the stack 625 RequestWorkersProcessCommandsStack(); 626 // Ask workers to exit 627 NewActionRequest(WorkerActionRequest::ENDWORKER); 628 // Now join threads. 629 #ifdef G4MULTITHREADED // protect here to prevent warning in compilation 630 while (!threads.empty()) { 631 G4Thread* t = *(threads.begin()); 632 threads.pop_front(); 633 userWorkerThreadInitialization->JoinWorker(t); 634 delete t; 635 } 636 #endif 637 threads.clear(); 638 } 639 640 // -------------------------------------------------------------------- 641 void G4MTRunManager::AbortRun(G4bool softAbort) 642 { 643 // This method is valid only for GeomClosed or EventProc state 644 G4ApplicationState currentState = G4StateManager::GetStateManager()->GetCurrentState(); 645 if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) { 646 runAborted = true; 647 MTkernel->BroadcastAbortRun(softAbort); 648 } 649 else { 650 G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl; 651 } 652 } 653 654 // -------------------------------------------------------------------- 655 void G4MTRunManager::AbortEvent() 656 { 657 // nothing to do in the master thread 658 } 659 660 // -------------------------------------------------------------------- 661 void G4MTRunManager::WaitForReadyWorkers() 662 { 663 beginOfEventLoopBarrier.Wait((G4int)GetNumberActiveThreads()); 664 endOfEventLoopBarrier.ResetCounter(); 665 beginOfEventLoopBarrier.ReleaseBarrier(); 666 } 667 668 // -------------------------------------------------------------------- 669 void G4MTRunManager::ThisWorkerReady() 670 { 671 beginOfEventLoopBarrier.ThisWorkerReady(); 672 } 673 674 // -------------------------------------------------------------------- 675 void G4MTRunManager::WaitForEndEventLoopWorkers() 676 { 677 endOfEventLoopBarrier.Wait((G4int)GetNumberActiveThreads()); 678 beginOfEventLoopBarrier.ResetCounter(); 679 endOfEventLoopBarrier.ReleaseBarrier(); 680 } 681 682 // -------------------------------------------------------------------- 683 void G4MTRunManager::ThisWorkerEndEventLoop() 684 { 685 endOfEventLoopBarrier.ThisWorkerReady(); 686 } 687 688 // -------------------------------------------------------------------- 689 void G4MTRunManager::NewActionRequest(G4MTRunManager::WorkerActionRequest newRequest) 690 { 691 nextActionRequestBarrier.Wait((G4int)GetNumberActiveThreads()); 692 // nextActionRequest is a shared resource, but there is no 693 // data-race thanks to the barrier: all threads are waiting 694 nextActionRequest = newRequest; 695 nextActionRequestBarrier.ReleaseBarrier(); 696 } 697 698 // -------------------------------------------------------------------- 699 G4MTRunManager::WorkerActionRequest G4MTRunManager::ThisWorkerWaitForNextAction() 700 { 701 nextActionRequestBarrier.ThisWorkerReady(); 702 return nextActionRequest; 703 } 704 705 // -------------------------------------------------------------------- 706 void G4MTRunManager::RequestWorkersProcessCommandsStack() 707 { 708 PrepareCommandsStack(); 709 NewActionRequest(WorkerActionRequest::PROCESSUI); 710 processUIBarrier.SetActiveThreads((G4int)GetNumberActiveThreads()); 711 processUIBarrier.WaitForReadyWorkers(); 712 } 713 714 // -------------------------------------------------------------------- 715 void G4MTRunManager::ThisWorkerProcessCommandsStackDone() 716 { 717 processUIBarrier.ThisWorkerReady(); 718 } 719 720 // -------------------------------------------------------------------- 721 void G4MTRunManager::SetPinAffinity(G4int n) 722 { 723 if (n == 0) { 724 G4Exception("G4MTRunManager::SetPinAffinity", "Run0114", FatalException, 725 "Pin affinity must be >0 or <0."); 726 } 727 pinAffinity = n; 728 return; 729 } 730