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 // 27 28 #include "G4TaskRunManager.hh" 29 30 #include "G4AutoLock.hh" 31 #include "G4EnvironmentUtils.hh" 32 #include "G4ProductionCutsTable.hh" 33 #include "G4Run.hh" 34 #include "G4ScoringManager.hh" 35 #include "G4StateManager.hh" 36 #include "G4Task.hh" 37 #include "G4TaskGroup.hh" 38 #include "G4TaskManager.hh" 39 #include "G4TaskRunManagerKernel.hh" 40 #include "G4ThreadLocalSingleton.hh" 41 #include "G4ThreadPool.hh" 42 #include "G4Threading.hh" 43 #include "G4Timer.hh" 44 #include "G4TransportationManager.hh" 45 #include "G4UImanager.hh" 46 #include "G4UserRunAction.hh" 47 #include "G4UserTaskInitialization.hh" 48 #include "G4UserTaskQueue.hh" 49 #include "G4UserTaskThreadInitialization.hh" 50 #include "G4VUserActionInitialization.hh" 51 #include "G4WorkerTaskRunManager.hh" 52 #include "G4WorkerThread.hh" 53 54 #include <cstdlib> 55 #include <cstring> 56 #include <iterator> 57 58 //============================================================================// 59 60 namespace 61 { 62 G4Mutex scorerMergerMutex; 63 G4Mutex runMergerMutex; 64 G4Mutex setUpEventMutex; 65 } // namespace 66 67 //============================================================================// 68 69 G4TaskRunManagerKernel* G4TaskRunManager::GetMTMasterRunManagerKernel() 70 { 71 return GetMasterRunManager()->MTkernel; 72 } 73 74 //============================================================================// 75 76 G4TaskRunManager::G4TaskRunManager(G4VUserTaskQueue* task_queue, G4bool useTBB, G4int grainsize) 77 : PTL::TaskRunManager(useTBB), eventGrainsize(grainsize) 78 { 79 if (task_queue != nullptr) taskQueue = task_queue; 80 81 // override default of 2 from G4MTRunManager 82 nworkers = G4Threading::G4GetNumberOfCores(); 83 fMasterRM = this; 84 MTkernel = static_cast<G4TaskRunManagerKernel*>(kernel); 85 86 G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators(); 87 if (numberOfStaticAllocators > 0) { 88 G4ExceptionDescription msg1; 89 msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n" 90 << "In multi-threaded mode, all G4Allocator objects must " 91 << "be dynamicly instantiated."; 92 G4Exception("G4TaskRunManager::G4TaskRunManager", "Run1035", FatalException, msg1); 93 } 94 95 G4UImanager::GetUIpointer()->SetMasterUIManager(true); 96 masterScM = G4ScoringManager::GetScoringManagerIfExist(); 97 98 // use default RandomNumberGenerator if created by user, or create default 99 masterRNGEngine = G4Random::getTheEngine(); 100 101 numberOfEventToBeProcessed = 0; 102 randDbl = new G4double[nSeedsPerEvent * nSeedsMax]; 103 104 //------------------------------------------------------------------------// 105 // handle threading 106 //------------------------------------------------------------------------// 107 auto _nthread_env = G4GetEnv<G4String>("G4FORCENUMBEROFTHREADS", ""); 108 for (auto& itr : _nthread_env) 109 itr = (char)std::tolower(itr); 110 111 if (_nthread_env == "max") 112 forcedNwokers = G4Threading::G4GetNumberOfCores(); 113 else if (!_nthread_env.empty()) { 114 std::stringstream ss; 115 G4int _nthread_val = -1; 116 ss << _nthread_env; 117 ss >> _nthread_val; 118 if (_nthread_val > 0) forcedNwokers = _nthread_val; 119 120 if (forcedNwokers > 0) nworkers = forcedNwokers; 121 } 122 123 //------------------------------------------------------------------------// 124 // option for forcing TBB 125 //------------------------------------------------------------------------// 126 #ifdef GEANT4_USE_TBB 127 G4int _useTBB = G4GetEnv<G4int>("G4FORCE_TBB", (G4int)useTBB); 128 if (_useTBB > 0) useTBB = true; 129 #else 130 if (useTBB) { 131 G4ExceptionDescription msg; 132 msg << "TBB was requested but Geant4 was not built with TBB support"; 133 G4Exception("G4TaskRunManager::G4TaskRunManager(...)", "Run0131", JustWarning, msg); 134 } 135 useTBB = false; 136 #endif 137 } 138 139 //============================================================================// 140 141 G4TaskRunManager::G4TaskRunManager(G4bool useTBB) : G4TaskRunManager(nullptr, useTBB, 0) {} 142 143 //============================================================================// 144 145 G4TaskRunManager::~G4TaskRunManager() 146 { 147 // terminate all the workers 148 G4TaskRunManager::TerminateWorkers(); 149 150 // trigger all G4AutoDelete instances 151 G4ThreadLocalSingleton<void>::Clear(); 152 153 // delete the task-group 154 delete workTaskGroup; 155 workTaskGroup = nullptr; 156 157 // destroy the thread-pool 158 if (threadPool != nullptr) threadPool->destroy_threadpool(); 159 160 PTL::TaskRunManager::Terminate(); 161 } 162 163 //============================================================================// 164 165 G4ThreadId G4TaskRunManager::GetMasterThreadId() 166 { 167 return G4MTRunManager::GetMasterThreadId(); 168 } 169 170 //============================================================================// 171 172 void G4TaskRunManager::StoreRNGStatus(const G4String& fn) 173 { 174 std::ostringstream os; 175 os << randomNumberStatusDir << "G4Master_" << fn << ".rndm"; 176 G4Random::saveEngineStatus(os.str().c_str()); 177 } 178 179 //============================================================================// 180 181 void G4TaskRunManager::SetNumberOfThreads(G4int n) 182 { 183 if (forcedNwokers > 0) { 184 if (verboseLevel > 0) { 185 G4ExceptionDescription msg; 186 msg << "\n### Number of threads is forced to " << forcedNwokers 187 << " by G4FORCENUMBEROFTHREADS environment variable. G4TaskRunManager::" << __FUNCTION__ 188 << "(" << n << ") ignored ###"; 189 G4Exception("G4TaskRunManager::SetNumberOfThreads(G4int)", "Run0132", JustWarning, msg); 190 } 191 nworkers = forcedNwokers; 192 } 193 else { 194 nworkers = n; 195 if (poolInitialized) { 196 if (verboseLevel > 0) { 197 std::stringstream ss; 198 ss << "\n### Thread-pool already initialized. Resizing to " << nworkers << "threads ###"; 199 G4cout << ss.str() << "\n" << G4endl; 200 } 201 GetThreadPool()->resize(n); 202 } 203 } 204 } 205 206 //============================================================================// 207 208 G4int G4TaskRunManager::GetNumberOfThreads() const 209 { 210 // If the ThreadPool isn't initialized, it will return 0 even if we've already 211 // set nworkers 212 return poolInitialized ? PTL::TaskRunManager::GetNumberOfThreads() : nworkers; 213 } 214 215 //============================================================================// 216 217 void G4TaskRunManager::Initialize() 218 { 219 G4bool firstTime = (threadPool == nullptr); 220 if (firstTime) InitializeThreadPool(); 221 222 G4RunManager::Initialize(); 223 224 // make sure all worker threads are set up. 225 G4RunManager::BeamOn(0); 226 if (firstTime) G4RunManager::SetRunIDCounter(0); 227 // G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true); 228 } 229 230 //============================================================================// 231 232 void G4TaskRunManager::InitializeThreadPool() 233 { 234 if (poolInitialized && (threadPool != nullptr) && (workTaskGroup != nullptr)) { 235 G4Exception("G4TaskRunManager::InitializeThreadPool", "Run1040", JustWarning, 236 "Threadpool already initialized. Ignoring..."); 237 return; 238 } 239 240 PTL::TaskRunManager::Initialize(nworkers); 241 242 // create the joiners 243 if (workTaskGroup == nullptr) { 244 workTaskGroup = new RunTaskGroup(threadPool); 245 } 246 247 if (verboseLevel > 0) { 248 std::stringstream ss; 249 ss.fill('='); 250 ss << std::setw(90) << ""; 251 G4cout << "\n" << ss.str() << G4endl; 252 253 if (threadPool->is_tbb_threadpool()) { 254 G4cout << "G4TaskRunManager :: Using TBB..." << G4endl; 255 } 256 else { 257 G4cout << "G4TaskRunManager :: Using G4ThreadPool..." << G4endl; 258 } 259 260 G4cout << ss.str() << "\n" << G4endl; 261 } 262 } 263 264 //============================================================================// 265 266 void G4TaskRunManager::ProcessOneEvent(G4int) 267 { 268 // Nothing to do 269 } 270 271 //============================================================================// 272 273 void G4TaskRunManager::TerminateOneEvent() 274 { 275 // Nothing to do 276 } 277 278 //============================================================================// 279 280 void G4TaskRunManager::ComputeNumberOfTasks() 281 { 282 G4int grainSize = (eventGrainsize == 0) ? (G4int)threadPool->size() : eventGrainsize; 283 grainSize = G4GetEnv<G4int>("G4FORCE_GRAINSIZE", grainSize, "Forcing grainsize..."); 284 if (grainSize == 0) grainSize = 1; 285 286 G4int nEvtsPerTask = 287 (numberOfEventToBeProcessed > grainSize) ? (numberOfEventToBeProcessed / grainSize) : 1; 288 289 if (eventModuloDef > 0) { 290 eventModulo = eventModuloDef; 291 } 292 else { 293 eventModulo = G4int(std::sqrt(G4double(numberOfEventToBeProcessed))); 294 if (eventModulo < 1) eventModulo = 1; 295 } 296 if (eventModulo > nEvtsPerTask) { 297 G4int oldMod = eventModulo; 298 eventModulo = nEvtsPerTask; 299 300 G4ExceptionDescription msgd; 301 msgd << "Event modulo is reduced to " << eventModulo << " (was " << oldMod << ")" 302 << " to distribute events to all threads."; 303 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10035", JustWarning, msgd); 304 } 305 nEvtsPerTask = eventModulo; 306 307 if (fakeRun) 308 nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask, 309 "Forcing number of events per task (overrides grainsize)..."); 310 else 311 nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask); 312 313 if (nEvtsPerTask < 1) nEvtsPerTask = 1; 314 315 numberOfTasks = numberOfEventToBeProcessed / nEvtsPerTask; 316 numberOfEventsPerTask = nEvtsPerTask; 317 eventModulo = numberOfEventsPerTask; 318 319 if (fakeRun && verboseLevel > 2) { 320 std::stringstream msg; 321 msg << "--> G4TaskRunManager::ComputeNumberOfTasks() --> " << numberOfTasks << " tasks with " 322 << numberOfEventsPerTask << " events/task..."; 323 324 std::stringstream ss; 325 ss.fill('='); 326 ss << std::setw((G4int)msg.str().length()) << ""; 327 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl; 328 } 329 } 330 331 //============================================================================// 332 333 void G4TaskRunManager::CreateAndStartWorkers() 334 { 335 // Now loop on requested number of workers 336 // This will also start the workers 337 // Currently we do not allow to change the 338 // number of threads: threads area created once 339 // Instead of pthread based workers, create tbbTask 340 static bool initializeStarted = false; 341 342 ComputeNumberOfTasks(); 343 344 if (fakeRun) { 345 if (initializeStarted) { 346 auto initCmdStack = GetCommandStack(); 347 if (!initCmdStack.empty()) { 348 threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() { 349 for (auto& itr : cmds) 350 G4UImanager::GetUIpointer()->ApplyCommand(itr); 351 G4WorkerTaskRunManager::GetWorkerRunManager()->DoWork(); 352 }); 353 } 354 } 355 else { 356 std::stringstream msg; 357 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> " 358 << "Initializing workers..."; 359 360 std::stringstream ss; 361 ss.fill('='); 362 ss << std::setw((G4int)msg.str().length()) << ""; 363 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl; 364 365 G4TaskRunManagerKernel::InitCommandStack() = GetCommandStack(); 366 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::InitializeWorker(); }); 367 } 368 initializeStarted = true; 369 } 370 else { 371 auto initCmdStack = GetCommandStack(); 372 if (!initCmdStack.empty()) { 373 threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() { 374 for (auto& itr : cmds) 375 G4UImanager::GetUIpointer()->ApplyCommand(itr); 376 }); 377 } 378 379 // cleans up a previous run and events in case a thread 380 // does not execute any tasks 381 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::ExecuteWorkerInit(); }); 382 383 { 384 std::stringstream msg; 385 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> " 386 << "Creating " << numberOfTasks << " tasks with " << numberOfEventsPerTask 387 << " events/task..."; 388 389 std::stringstream ss; 390 ss.fill('='); 391 ss << std::setw((G4int)msg.str().length()) << ""; 392 G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl; 393 } 394 395 G4int remaining = numberOfEventToBeProcessed; 396 for (G4int nt = 0; nt < numberOfTasks + 1; ++nt) { 397 if (remaining > 0) AddEventTask(nt); 398 remaining -= numberOfEventsPerTask; 399 } 400 workTaskGroup->wait(); 401 } 402 } 403 404 //============================================================================// 405 406 void G4TaskRunManager::AddEventTask(G4int nt) 407 { 408 if (verboseLevel > 3) G4cout << "Adding task " << nt << " to task-group..." << G4endl; 409 workTaskGroup->exec([this, nt]() { 410 if (verboseLevel > 3) G4cout << "Starting task " << nt << "..." << G4endl; 411 G4TaskRunManagerKernel::ExecuteWorkerTask(); 412 }); 413 } 414 415 //============================================================================// 416 417 void G4TaskRunManager::RefillSeeds() 418 { 419 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 420 G4int nFill = 0; 421 switch (SeedOncePerCommunication()) { 422 case 0: 423 nFill = numberOfEventToBeProcessed - nSeedsFilled; 424 break; 425 case 1: 426 nFill = numberOfTasks - nSeedsFilled; 427 break; 428 case 2: 429 default: 430 nFill = (numberOfEventToBeProcessed - nSeedsFilled * eventModulo) / eventModulo + 1; 431 } 432 // Generates up to nSeedsMax seed pairs only. 433 if (nFill > nSeedsMax) nFill = nSeedsMax; 434 masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl); 435 helper->Refill(randDbl, nFill); 436 nSeedsFilled += nFill; 437 } 438 439 //============================================================================// 440 441 void G4TaskRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select) 442 { 443 MTkernel->SetUpDecayChannels(); 444 numberOfEventToBeProcessed = n_event; 445 numberOfEventProcessed = 0; 446 447 if (!fakeRun) { 448 nSeedsUsed = 0; 449 nSeedsFilled = 0; 450 451 if (verboseLevel > 0) timer->Start(); 452 453 n_select_msg = n_select; 454 if (macroFile != nullptr) { 455 if (n_select_msg < 0) n_select_msg = n_event; 456 457 msgText = "/control/execute "; 458 msgText += macroFile; 459 selectMacro = macroFile; 460 } 461 else { 462 n_select_msg = -1; 463 selectMacro = ""; 464 } 465 466 ComputeNumberOfTasks(); 467 468 // initialize seeds 469 // If user did not implement InitializeSeeds, 470 // use default: nSeedsPerEvent seeds per event 471 472 if (n_event > 0) { 473 G4bool _overload = InitializeSeeds(n_event); 474 G4bool _functor = false; 475 if (!_overload) _functor = initSeedsCallback(n_event, nSeedsPerEvent, nSeedsFilled); 476 if (!_overload && !_functor) { 477 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 478 switch (SeedOncePerCommunication()) { 479 case 0: 480 nSeedsFilled = n_event; 481 break; 482 case 1: 483 nSeedsFilled = numberOfTasks; 484 break; 485 case 2: 486 nSeedsFilled = n_event / eventModulo + 1; 487 break; 488 default: 489 G4ExceptionDescription msgd; 490 msgd << "Parameter value <" << SeedOncePerCommunication() 491 << "> of seedOncePerCommunication is invalid. It is reset " 492 "to 0."; 493 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd); 494 SetSeedOncePerCommunication(0); 495 nSeedsFilled = n_event; 496 } 497 498 // Generates up to nSeedsMax seed pairs only. 499 if (nSeedsFilled > nSeedsMax) nSeedsFilled = nSeedsMax; 500 masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl); 501 helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent); 502 } 503 } 504 } 505 506 // Now initialize workers. Check if user defined a WorkerThreadInitialization 507 if (userWorkerThreadInitialization == nullptr) 508 userWorkerThreadInitialization = new G4UserTaskThreadInitialization(); 509 510 // Prepare UI commands for threads 511 PrepareCommandsStack(); 512 513 // Start worker threads 514 CreateAndStartWorkers(); 515 } 516 517 //============================================================================// 518 519 void G4TaskRunManager::RunTermination() 520 { 521 // Wait for all worker threads to have finished the run 522 // i.e. wait for them to return from RunTermination() 523 // This guarantee that userrunaction for workers has been called 524 525 // Wait now for all threads to finish event-loop 526 WaitForEndEventLoopWorkers(); 527 // Now call base-class methof 528 G4RunManager::TerminateEventLoop(); 529 G4RunManager::RunTermination(); 530 } 531 532 //============================================================================// 533 534 void G4TaskRunManager::ConstructScoringWorlds() 535 { 536 masterScM = G4ScoringManager::GetScoringManagerIfExist(); 537 // Call base class stuff... 538 G4RunManager::ConstructScoringWorlds(); 539 540 GetMasterWorlds().clear(); 541 auto nWorlds = (G4int)G4TransportationManager::GetTransportationManager()->GetNoWorlds(); 542 auto itrW = G4TransportationManager::GetTransportationManager()->GetWorldsIterator(); 543 for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) { 544 addWorld(iWorld, *itrW); 545 ++itrW; 546 } 547 } 548 549 //============================================================================// 550 551 void G4TaskRunManager::MergeScores(const G4ScoringManager* localScoringManager) 552 { 553 G4AutoLock l(&scorerMergerMutex); 554 if (masterScM != nullptr) masterScM->Merge(localScoringManager); 555 } 556 557 //============================================================================// 558 559 void G4TaskRunManager::MergeRun(const G4Run* localRun) 560 { 561 G4AutoLock l(&runMergerMutex); 562 if (currentRun != nullptr) currentRun->Merge(localRun); 563 } 564 565 //============================================================================// 566 567 G4bool G4TaskRunManager::SetUpAnEvent(G4Event* evt, G4long& s1, G4long& s2, G4long& s3, 568 G4bool reseedRequired) 569 { 570 G4AutoLock l(&setUpEventMutex); 571 if (numberOfEventProcessed < numberOfEventToBeProcessed) { 572 evt->SetEventID(numberOfEventProcessed); 573 if (reseedRequired) { 574 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 575 G4int idx_rndm = nSeedsPerEvent * nSeedsUsed; 576 s1 = helper->GetSeed(idx_rndm); 577 s2 = helper->GetSeed(idx_rndm + 1); 578 if (nSeedsPerEvent == 3) s3 = helper->GetSeed(idx_rndm + 2); 579 ++nSeedsUsed; 580 if (nSeedsUsed == nSeedsFilled) RefillSeeds(); 581 } 582 numberOfEventProcessed++; 583 return true; 584 } 585 return false; 586 } 587 588 //============================================================================// 589 590 G4int G4TaskRunManager::SetUpNEvents(G4Event* evt, G4SeedsQueue* seedsQueue, G4bool reseedRequired) 591 { 592 G4AutoLock l(&setUpEventMutex); 593 if (numberOfEventProcessed < numberOfEventToBeProcessed && !runAborted) { 594 G4int nevt = numberOfEventsPerTask; 595 G4int nmod = eventModulo; 596 if (numberOfEventProcessed + nevt > numberOfEventToBeProcessed) { 597 nevt = numberOfEventToBeProcessed - numberOfEventProcessed; 598 nmod = numberOfEventToBeProcessed - numberOfEventProcessed; 599 } 600 evt->SetEventID(numberOfEventProcessed); 601 602 if (reseedRequired) { 603 G4RNGHelper* helper = G4RNGHelper::GetInstance(); 604 G4int nevRnd = nmod; 605 if (SeedOncePerCommunication() > 0) nevRnd = 1; 606 for (G4int i = 0; i < nevRnd; ++i) { 607 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed)); 608 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1)); 609 if (nSeedsPerEvent == 3) seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2)); 610 nSeedsUsed++; 611 if (nSeedsUsed == nSeedsFilled) RefillSeeds(); 612 } 613 } 614 numberOfEventProcessed += nevt; 615 return nevt; 616 } 617 return 0; 618 } 619 620 //============================================================================// 621 622 void G4TaskRunManager::TerminateWorkers() 623 { 624 // Force workers to execute (if any) all UI commands left in the stack 625 RequestWorkersProcessCommandsStack(); 626 627 if (workTaskGroup != nullptr) { 628 workTaskGroup->join(); 629 if (!fakeRun) 630 threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::TerminateWorker(); }); 631 } 632 } 633 634 //============================================================================// 635 636 void G4TaskRunManager::AbortRun(G4bool softAbort) 637 { 638 // This method is valid only for GeomClosed or EventProc state 639 G4ApplicationState currentState = G4StateManager::GetStateManager()->GetCurrentState(); 640 if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) { 641 runAborted = true; 642 MTkernel->BroadcastAbortRun(softAbort); 643 } 644 else { 645 G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl; 646 } 647 } 648 649 //============================================================================// 650 651 void G4TaskRunManager::AbortEvent() 652 { 653 // nothing to do in the master thread 654 } 655 656 //============================================================================// 657 658 void G4TaskRunManager::WaitForEndEventLoopWorkers() 659 { 660 if (workTaskGroup != nullptr) { 661 workTaskGroup->join(); 662 if (!fakeRun) 663 threadPool->execute_on_all_threads( 664 []() { G4TaskRunManagerKernel::TerminateWorkerRunEventLoop(); }); 665 } 666 } 667 668 //============================================================================// 669 670 void G4TaskRunManager::RequestWorkersProcessCommandsStack() 671 { 672 PrepareCommandsStack(); 673 674 auto process_commands_stack = []() { 675 G4MTRunManager* mrm = G4MTRunManager::GetMasterRunManager(); 676 if (mrm != nullptr) { 677 auto cmds = mrm->GetCommandStack(); 678 for (const auto& itr : cmds) 679 G4UImanager::GetUIpointer()->ApplyCommand(itr); // TLS instance 680 mrm->ThisWorkerProcessCommandsStackDone(); 681 } 682 }; 683 684 if (threadPool != nullptr) threadPool->execute_on_all_threads(process_commands_stack); 685 } 686 687 //============================================================================// 688 689 void G4TaskRunManager::ThisWorkerProcessCommandsStackDone() {} 690 691 //============================================================================// 692