Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4TaskRunManager.cc
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//
27
28#include "G4TaskRunManager.hh"
29#include "G4AutoLock.hh"
30#include "G4EnvironmentUtils.hh"
32#include "G4Run.hh"
33#include "G4ScoringManager.hh"
34#include "G4StateManager.hh"
35#include "G4Task.hh"
36#include "G4TaskGroup.hh"
37#include "G4TaskManager.hh"
39#include "G4ThreadPool.hh"
40#include "G4Threading.hh"
41#include "G4TiMemory.hh"
42#include "G4Timer.hh"
44#include "G4UImanager.hh"
45#include "G4UserRunAction.hh"
50#include "G4WorkerThread.hh"
51#include "G4UserTaskQueue.hh"
52#include "G4TiMemory.hh"
53
54#include <cstdlib>
55#include <cstring>
56#include <iterator>
57
58//============================================================================//
59
60namespace
61{
62 G4Mutex scorerMergerMutex;
63 G4Mutex runMergerMutex;
64 G4Mutex setUpEventMutex;
65} // namespace
66
67//============================================================================//
68
70{
71 return GetMasterRunManager()->MTkernel;
72}
73
74//============================================================================//
75
77 G4int grainsize)
79 , PTL::TaskRunManager(useTBB)
80 , eventGrainsize(grainsize)
81 , numberOfEventsPerTask(-1)
82 , numberOfTasks(-1)
83 , masterRNGEngine(nullptr)
84 , workTaskGroup(nullptr)
85{
86 if(task_queue)
87 taskQueue = task_queue;
88
89 // override default of 2 from G4MTRunManager
90 nworkers = std::thread::hardware_concurrency();
91 fMasterRM = this;
92 MTkernel = static_cast<G4TaskRunManagerKernel*>(kernel);
93
94 G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
95 if(numberOfStaticAllocators > 0)
96 {
98 msg1 << "There are " << numberOfStaticAllocators
99 << " static G4Allocator objects detected.\n"
100 << "In multi-threaded mode, all G4Allocator objects must "
101 << "be dynamicly instantiated.";
102 G4Exception("G4TaskRunManager::G4TaskRunManager", "Run1035", FatalException,
103 msg1);
104 }
105
108
109 // use default RandomNumberGenerator if created by user, or create default
110 masterRNGEngine = G4Random::getTheEngine();
111
114
115 //------------------------------------------------------------------------//
116 // handle threading
117 //------------------------------------------------------------------------//
118 G4String _nthread_env = G4GetEnv<G4String>("G4FORCENUMBEROFTHREADS", "max");
119 for(auto& itr : _nthread_env)
120 itr = tolower(itr);
121
122 if(_nthread_env == "max")
124 else
125 {
126 std::stringstream ss;
127 G4int _nthread_val = -1;
128 ss << _nthread_env;
129 ss >> _nthread_val;
130 if(_nthread_val > 0)
131 forcedNwokers = _nthread_val;
132
133 if(forcedNwokers > 0)
135 }
136
137 //------------------------------------------------------------------------//
138 // option for forcing TBB
139 //------------------------------------------------------------------------//
140#ifdef GEANT4_USE_TBB
141 G4int _useTBB = G4GetEnv<G4int>("G4FORCE_TBB", (G4int) useTBB);
142 if(_useTBB > 0)
143 useTBB = true;
144#else
145 if(useTBB)
146 {
148 msg << "TBB was requested but Geant4 was not built with TBB support";
149 G4Exception("G4TaskRunManager::G4TaskRunManager(...)", "Run0131",
150 JustWarning, msg);
151 }
152 useTBB = false;
153#endif
154
155 // handle TBB
157}
158
159//============================================================================//
160
162 : G4TaskRunManager(nullptr, useTBB, 0)
163{}
164
165//============================================================================//
166
168{
169 if(workTaskGroup)
170 {
172 delete workTaskGroup;
173 }
174 // finalize profiler before shutting down the threads
176 if(threadPool)
179}
180
181//============================================================================//
182
184{
186}
187
188//============================================================================//
189
191{
192 std::ostringstream os;
193 os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
194 G4Random::saveEngineStatus(os.str().c_str());
195}
196
197//============================================================================//
198
200{
201 if(forcedNwokers > 0)
202 {
203 std::stringstream ss;
204 ss << "\n### Number of threads is forced to " << forcedNwokers
205 << " by G4FORCENUMBEROFTHREADS environment variable. G4TaskRunManager::"
206 << __FUNCTION__ << "(" << n << ") ignored ###";
207
208 if(verboseLevel > 1)
209 {
211 msg << ss.str();
212 G4Exception("G4TaskRunManager::SetNumberOfThreads(G4int)", "Run0132",
213 JustWarning, msg);
214 }
215 else
216 {
217 G4cout << ss.str() << "\n" << G4endl;
218 }
220 }
221 else
222 {
223 nworkers = n;
225 {
226 std::stringstream ss;
227 ss << "\n### Thread-pool already initialized. Resizing to " << nworkers
228 << "threads ###";
229 G4cout << ss.str() << "\n" << G4endl;
230 GetThreadPool()->resize(n);
231 }
232 }
233}
234
235//============================================================================//
236
238{
239 G4bool firstTime = (!threadPool);
240 if(firstTime)
242
244
245 // make sure all worker threads are set up.
247 if(firstTime)
249 // G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true);
250}
251
252//============================================================================//
253
255{
257 {
258 G4Exception("G4TaskRunManager::InitializeThreadPool", "Run1040",
259 JustWarning, "Threadpool already initialized. Ignoring...");
260 return;
261 }
262
263 std::stringstream ss;
264 ss.fill('=');
265 ss << std::setw(90) << "";
266 G4cout << "\n" << ss.str() << G4endl;
267
270
271 // create the joiners
272 if(threadPool->using_tbb())
273 {
274 G4cout << "G4TaskRunManager :: Using TBB..." << G4endl;
275 if(!workTaskGroup)
277 }
278 else
279 {
280 G4cout << "G4TaskRunManager :: Using G4ThreadPool..." << G4endl;
281 if(!workTaskGroup)
283 }
284
285 G4cout << ss.str() << "\n" << G4endl;
286}
287
288//============================================================================//
289
291{
292 // Nothing to do
293}
294
295//============================================================================//
296
298{
299 // Nothing to do
300}
301
302//============================================================================//
303
305{
306 G4int grainSize = (eventGrainsize == 0) ? threadPool->size() : eventGrainsize;
307 grainSize =
308 G4GetEnv<G4int>("G4FORCE_GRAINSIZE", grainSize, "Forcing grainsize...");
309 if(grainSize == 0)
310 grainSize = 1;
311
312 G4int nEvtsPerTask = (numberOfEventToBeProcessed > grainSize)
313 ? (numberOfEventToBeProcessed / grainSize)
314 : 1;
315
316 if(fakeRun)
317 nEvtsPerTask = G4GetEnv<G4int>(
318 "G4FORCE_EVENTS_PER_TASK", nEvtsPerTask,
319 "Forcing number of events per task (overrides grainsize)...");
320 else
321 nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask);
322
323 if(nEvtsPerTask < 1)
324 nEvtsPerTask = 1;
325
326 numberOfTasks = numberOfEventToBeProcessed / nEvtsPerTask;
327 numberOfEventsPerTask = nEvtsPerTask;
328 eventModulo = numberOfEventsPerTask;
329
330 if(fakeRun && verboseLevel > 1)
331 {
332 std::stringstream msg;
333 msg << "--> G4TaskRunManager::ComputeNumberOfTasks() --> " << numberOfTasks
334 << " tasks with " << numberOfEventsPerTask << " events/task...";
335
336 std::stringstream ss;
337 ss.fill('=');
338 ss << std::setw(msg.str().length()) << "";
339 G4cout << "\n"
340 << ss.str() << "\n"
341 << msg.str() << "\n"
342 << ss.str() << "\n"
343 << G4endl;
344 }
345}
346
347//============================================================================//
348
350{
351 // Now loop on requested number of workers
352 // This will also start the workers
353 // Currently we do not allow to change the
354 // number of threads: threads area created once
355 // Instead of pthread based workers, create tbbTask
356 static bool initializeStarted = false;
357
359
360 if(fakeRun)
361 {
362 if(initializeStarted)
363 {
364 auto initCmdStack = GetCommandStack();
365 if(!initCmdStack.empty())
366 {
367 threadPool->execute_on_all_threads([initCmdStack]() {
368 for(auto& itr : initCmdStack)
369 G4UImanager::GetUIpointer()->ApplyCommand(itr);
371 });
372 }
373 }
374 else
375 {
376 std::stringstream msg;
377 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
378 << "Initializing workers...";
379
380 std::stringstream ss;
381 ss.fill('=');
382 ss << std::setw(msg.str().length()) << "";
383 G4cout << "\n"
384 << ss.str() << "\n"
385 << msg.str() << "\n"
386 << ss.str() << "\n"
387 << G4endl;
388
392 }
393 initializeStarted = true;
394 }
395 else
396 {
397 auto initCmdStack = GetCommandStack();
398 if(!initCmdStack.empty())
399 {
400 threadPool->execute_on_all_threads([initCmdStack]() {
401 for(auto& itr : initCmdStack)
402 G4UImanager::GetUIpointer()->ApplyCommand(itr);
403 });
404 }
405
406 // cleans up a previous run and events in case a thread
407 // does not execute any tasks
410
411 {
412 std::stringstream msg;
413 msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
414 << "Creating " << numberOfTasks << " tasks with "
415 << numberOfEventsPerTask << " events/task...";
416
417 std::stringstream ss;
418 ss.fill('=');
419 ss << std::setw(msg.str().length()) << "";
420 G4cout << "\n"
421 << ss.str() << "\n"
422 << msg.str() << "\n"
423 << ss.str() << "\n"
424 << G4endl;
425 }
426
428 for(G4int nt = 0; nt < numberOfTasks + 1; ++nt)
429 {
430 if(remaining > 0)
431 AddEventTask(nt);
432 remaining -= numberOfEventsPerTask;
433 }
435 }
436}
437
438//============================================================================//
439
441{
442 if(verboseLevel > 1)
443 G4cout << "Adding task " << nt << " to task-group..." << G4endl;
445}
446
447//============================================================================//
448
450{
452 G4int nFill = 0;
454 {
455 case 0:
457 break;
458 case 1:
459 nFill = numberOfEventsPerTask - nSeedsFilled;
460 break;
461 case 2:
462 default:
465 1;
466 }
467 // Generates up to nSeedsMax seed pairs only.
468 if(nFill > nSeedsMax)
469 nFill = nSeedsMax;
470 masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl);
471 helper->Refill(randDbl, nFill);
472 nSeedsFilled += nFill;
473}
474
475//============================================================================//
476
477void G4TaskRunManager::InitializeEventLoop(G4int n_event, const char* macroFile,
478 G4int n_select)
479{
480 MTkernel->SetUpDecayChannels();
483
484 if(!fakeRun)
485 {
486 nSeedsUsed = 0;
487 nSeedsFilled = 0;
488
489 if(verboseLevel > 0)
490 timer->Start();
491
492 n_select_msg = n_select;
493 if(macroFile != nullptr)
494 {
495 if(n_select_msg < 0)
496 n_select_msg = n_event;
497
498 msgText = "/control/execute ";
499 msgText += macroFile;
500 selectMacro = macroFile;
501 }
502 else
503 {
504 n_select_msg = -1;
505 selectMacro = "";
506 }
507
509
510 // initialize seeds
511 // If user did not implement InitializeSeeds,
512 // use default: nSeedsPerEvent seeds per event
513 if(eventModuloDef > 0)
514 {
516 if(eventModulo > numberOfEventsPerTask)
517 {
518 G4int oldMod = eventModulo;
519 eventModulo = numberOfEventsPerTask;
520 if(eventModulo < 1)
521 eventModulo = 1;
522
524 msgd << "Event modulo is reduced to " << eventModulo << " (was "
525 << oldMod << ")"
526 << " to distribute events to all threads.";
527 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10035",
528 JustWarning, msgd);
529 }
530 }
531 else
532 {
533 eventModulo = G4int(std::sqrt(G4double(numberOfEventsPerTask)));
534 if(eventModulo < 1)
535 eventModulo = 1;
536 }
537
538 if(n_event > 0)
539 {
540 G4bool _overload = InitializeSeeds(n_event);
541 G4bool _functor = false;
542 if(!_overload)
543 _functor = initSeedsCallback(n_event, nSeedsPerEvent, nSeedsFilled);
544 if(_overload == false && _functor == false)
545 {
548 {
549 case 0:
550 nSeedsFilled = n_event;
551 break;
552 case 1:
553 nSeedsFilled = numberOfEventsPerTask;
554 break;
555 case 2:
556 nSeedsFilled = n_event / eventModulo + 1;
557 break;
558 default:
560 msgd << "Parameter value <" << SeedOncePerCommunication()
561 << "> of seedOncePerCommunication is invalid. It is reset "
562 "to 0.";
563 G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10036",
564 JustWarning, msgd);
566 nSeedsFilled = n_event;
567 }
568
569 // Generates up to nSeedsMax seed pairs only.
572 masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl);
573 helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent);
574 }
575 }
576 }
577
578 // Now initialize workers. Check if user defined a WorkerThreadInitialization
579 if(userWorkerThreadInitialization == nullptr)
581
582 // Prepare UI commands for threads
584
585 // Start worker threads
587}
588
589//============================================================================//
590
592{
593 // Wait for all worker threads to have finished the run
594 // i.e. wait for them to return from RunTermination()
595 // This guarantee that userrunaction for workers has been called
596
597 // Wait now for all threads to finish event-loop
599 // Now call base-class methof
602}
603
604//============================================================================//
605
607{
609 // Call base class stuff...
611
612 masterWorlds.clear();
613 size_t nWorlds =
615 std::vector<G4VPhysicalVolume*>::iterator itrW =
617 for(size_t iWorld = 0; iWorld < nWorlds; ++iWorld)
618 {
619 addWorld(iWorld, *itrW);
620 ++itrW;
621 }
622}
623
624//============================================================================//
625
626void G4TaskRunManager::MergeScores(const G4ScoringManager* localScoringManager)
627{
628 G4AutoLock l(&scorerMergerMutex);
629 if(masterScM)
630 masterScM->Merge(localScoringManager);
631}
632
633//============================================================================//
634
636{
637 G4AutoLock l(&runMergerMutex);
638 if(currentRun)
639 currentRun->Merge(localRun);
640}
641
642//============================================================================//
643
645 G4long& s3, G4bool reseedRequired)
646{
647 G4AutoLock l(&setUpEventMutex);
649 {
651 if(reseedRequired)
652 {
654 G4int idx_rndm = nSeedsPerEvent * nSeedsUsed;
655 s1 = helper->GetSeed(idx_rndm);
656 s2 = helper->GetSeed(idx_rndm + 1);
657 if(nSeedsPerEvent == 3)
658 s3 = helper->GetSeed(idx_rndm + 2);
659 ++nSeedsUsed;
661 RefillSeeds();
662 }
664 return true;
665 }
666 return false;
667}
668
669//============================================================================//
670
672 G4bool reseedRequired)
673{
674 G4AutoLock l(&setUpEventMutex);
676 {
677 G4int nevt = numberOfEventsPerTask;
678 G4int nmod = eventModulo;
680 {
683 }
685 if(reseedRequired)
686 {
688 G4int nevRnd = nmod;
690 nevRnd = 1;
691 for(G4int i = 0; i < nevRnd; ++i)
692 {
693 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed));
694 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1));
695 if(nSeedsPerEvent == 3)
696 seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2));
697 nSeedsUsed++;
699 RefillSeeds();
700 }
701 }
703 return nevt;
704 }
705 return 0;
706}
707
708//============================================================================//
709
711{
712 // Force workers to execute (if any) all UI commands left in the stack
714
715 if(workTaskGroup)
716 {
718 if(!fakeRun)
721 }
722}
723
724//============================================================================//
725
727{
728 // This method is valid only for GeomClosed or EventProc state
729 G4ApplicationState currentState =
731 if(currentState == G4State_GeomClosed || currentState == G4State_EventProc)
732 {
733 runAborted = true;
734 MTkernel->BroadcastAbortRun(softAbort);
735 }
736 else
737 {
738 G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
739 }
740}
741
742//============================================================================//
743
745{
746 // nothing to do in the master thread
747}
748
749//============================================================================//
750
752{
753 if(workTaskGroup)
754 {
756 if(!fakeRun)
759 }
760}
761
762//============================================================================//
763
765{
767
768 auto process_commands_stack = []() {
770 if(mrm)
771 {
772 auto cmds = mrm->GetCommandStack();
773 for(const auto& itr : cmds)
774 G4UImanager::GetUIpointer()->ApplyCommand(itr); // TLS instance
776 }
777 };
778
779 threadPool->execute_on_all_threads(process_commands_stack);
780}
781
782//============================================================================//
783
785
786//============================================================================//
G4ApplicationState
@ G4State_EventProc
@ G4State_GeomClosed
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
std::queue< G4long > G4SeedsQueue
Definition: G4RNGHelper.hh:133
G4Thread::id G4ThreadId
Definition: G4Threading.hh:286
std::mutex G4Mutex
Definition: G4Threading.hh:81
double G4double
Definition: G4Types.hh:83
long G4long
Definition: G4Types.hh:87
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
virtual void flatArray(const int size, double *vect)=0
void SetEventID(G4int i)
Definition: G4Event.hh:80
static G4int SeedOncePerCommunication()
static void SetSeedOncePerCommunication(G4int val)
G4int numberOfEventToBeProcessed
virtual void ThisWorkerProcessCommandsStackDone()
static void addWorld(G4int counter, G4VPhysicalVolume *w)
virtual void PrepareCommandsStack()
static G4MTRUN_DLL G4ScoringManager * masterScM
static G4MTRUN_DLL G4MTRunManager * fMasterRM
static G4MTRUN_DLL masterWorlds_t masterWorlds
static G4MTRunManager * GetMasterRunManager()
static G4ThreadId GetMasterThreadId()
std::vector< G4String > GetCommandStack()
static void Finalize()
Definition: G4Profiler.cc:331
G4int GetNumberOfStaticAllocators() const
virtual void Initialize()
G4Timer * timer
void SetRunIDCounter(G4int i)
G4UserWorkerThreadInitialization * userWorkerThreadInitialization
G4int n_select_msg
G4int numberOfEventProcessed
virtual void BeamOn(G4int n_event, const char *macroFile=0, G4int n_select=-1)
G4RunManagerKernel * kernel
G4int verboseLevel
G4Run * currentRun
G4bool runAborted
G4String msgText
G4String selectMacro
virtual void RunTermination()
G4String randomNumberStatusDir
virtual void TerminateEventLoop()
virtual void ConstructScoringWorlds()
Definition: G4Run.hh:49
virtual void Merge(const G4Run *)
Definition: G4Run.cc:64
void Merge(const G4ScoringManager *scMan)
static G4ScoringManager * GetScoringManagerIfExist()
const G4ApplicationState & GetCurrentState() const
static G4StateManager * GetStateManager()
void BroadcastAbortRun(G4bool softAbort)
static std::vector< G4String > & InitCommandStack()
virtual void ConstructScoringWorlds() override
virtual void InitializeThreadPool() override
virtual void CreateAndStartWorkers() override
static G4TaskRunManager * GetMasterRunManager()
virtual G4bool InitializeSeeds(G4int) override
virtual void ThisWorkerProcessCommandsStackDone() override
virtual G4int SetUpNEvents(G4Event *, G4SeedsQueue *seedsQueue, G4bool reseedRequired=true) override
G4VUserTaskQueue *& taskQueue
virtual void SetNumberOfThreads(G4int n) override
virtual void AbortRun(G4bool softAbort=false) override
InitializeSeedsCallback initSeedsCallback
virtual void RefillSeeds() override
virtual void RequestWorkersProcessCommandsStack() override
virtual void AddEventTask(G4int)
static G4ThreadId GetMasterThreadId()
virtual void TerminateOneEvent() override
RunTaskGroup * workTaskGroup
virtual void TerminateWorkers() override
virtual void AbortEvent() override
virtual void InitializeEventLoop(G4int n_event, const char *macroFile=nullptr, G4int n_select=-1) override
virtual ~G4TaskRunManager()
G4TBBTaskGroup< void > RunTaskGroupTBB
virtual void Initialize() override
virtual void StoreRNGStatus(const G4String &filenamePrefix) override
virtual void RunTermination() override
void MergeScores(const G4ScoringManager *localScoringManager)
virtual void WaitForEndEventLoopWorkers() override
G4TaskGroup< void > RunTaskGroup
G4ThreadPool *& threadPool
static G4TaskRunManagerKernel * GetMTMasterRunManagerKernel()
virtual void ProcessOneEvent(G4int i_event) override
void MergeRun(const G4Run *localRun)
virtual void ComputeNumberOfTasks()
G4TaskRunManager(G4bool useTBB=G4GetEnv< G4bool >("G4USE_TBB", false))
virtual G4bool SetUpAnEvent(G4Event *, G4long &s1, G4long &s2, G4long &s3, G4bool reseedRequired=true) override
static G4TemplateRNGHelper< T > * GetInstance()
Definition: G4RNGHelper.cc:37
virtual const T GetSeed(const G4int &sdId)
Definition: G4RNGHelper.hh:58
void Fill(G4double *dbl, G4int nev, G4int nev_tot, G4int nrpe)
Definition: G4RNGHelper.hh:77
void Refill(G4double *dbl, G4int nev)
Definition: G4RNGHelper.hh:90
void Start()
static G4TransportationManager * GetTransportationManager()
std::vector< G4VPhysicalVolume * >::iterator GetWorldsIterator()
size_t GetNoWorlds() const
G4int ApplyCommand(const char *aCommand)
Definition: G4UImanager.cc:485
void SetMasterUIManager(G4bool val)
Definition: G4UImanager.hh:212
static G4UImanager * GetUIpointer()
Definition: G4UImanager.cc:77
virtual void DoWork() override
static G4WorkerTaskRunManager * GetWorkerRunManager()
Up join(Up accum={})
Definition: TaskGroup.hh:274
void exec(Func &&func, Args... args)
Definition: TaskGroup.hh:215
int GetVerbose() const
virtual void Initialize(uint64_t n=std::thread::hardware_concurrency())
virtual void Terminate()
void SetVerbose(int val)
ThreadPool * GetThreadPool() const
static bool using_tbb()
Definition: ThreadPool.cc:92
void resize(size_type _n)
Definition: ThreadPool.hh:287
static void set_use_tbb(bool val)
Definition: ThreadPool.cc:100
void execute_on_all_threads(FuncT &&_func)
Definition: ThreadPool.hh:375
size_type size() const
Definition: ThreadPool.hh:151
size_type destroy_threadpool()
Definition: ThreadPool.cc:366
virtual void wait()
Definition: VTaskGroup.cc:81
G4int G4GetNumberOfCores()
Definition: G4Threading.cc:121
Definition: AutoLock.hh:254