HTGS  v2.0
The Hybrid Task Graph Scheduler
AnyTaskManager.hpp
Go to the documentation of this file.
1 // NIST-developed software is provided by NIST as a public service. You may use, copy and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software.
2 // NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE.
3 // You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States.
4 
12 #ifndef HTGS_ANYTASKMANAGER_HPP
13 #define HTGS_ANYTASKMANAGER_HPP
14 
15 #include <atomic>
16 #include <memory>
17 #include <vector>
18 
19 #include <htgs/types/Types.hpp>
24 #ifdef USE_NVTX
25 #include <nvtx3/nvToolsExt.h>
26 #endif
27 
28 #ifdef WS_PROFILE
29 #include <htgs/core/graph/profile/ProfileData.hpp>
30 #include <htgs/core/graph/profile/CustomProfile.hpp>
31 #endif
32 
33 namespace htgs {
34 class TaskManagerThread;
35 
46  public:
47 
56  AnyTaskManager(size_t numThreads, bool isStartTask, size_t pipelineId, size_t numPipelines, std::string address) {
57  this->taskComputeTime = 0L;
58  this->taskWaitTime = 0L;
59  this->poll = false;
60  this->timeout = 0L;
61  this->numThreads = numThreads;
62  this->threadId = 0;
63  this->startTask = isStartTask;
64  this->pipelineId = pipelineId;
65  this->numPipelines = numPipelines;
66  this->alive = true;
67  this->initialized = false;
68  this->address = address;
69  }
70 
82  bool isStartTask,
83  bool poll,
84  size_t microTimeoutTime,
85  size_t pipelineId,
86  size_t numPipelines,
87  std::string address) {
88  this->taskComputeTime = 0L;
89  this->taskWaitTime = 0L;
90  this->poll = poll;
91  this->timeout = microTimeoutTime;
92  this->numThreads = numThreads;
93  this->threadId = 0;
94  this->startTask = isStartTask;
95  this->pipelineId = pipelineId;
96  this->numPipelines = numPipelines;
97  this->alive = true;
98  this->initialized = false;
99  this->address = address;
100  }
101 
105 
109  virtual ~AnyTaskManager() { };
110 
115  virtual AnyITask *getTaskFunction() = 0;
116 
121  virtual std::shared_ptr<AnyConnector> getInputConnector() = 0;
122 
127  virtual std::shared_ptr<AnyConnector> getOutputConnector() = 0;
128 
134  virtual AnyTaskManager *copy(bool deep) = 0;
135 
139  virtual void initialize() = 0;
140 
158  virtual void executeTask() = 0;
159 
164  virtual void setRuntimeThread(TaskManagerThread *runtimeThread) = 0;
165 
170  virtual void setInputConnector(std::shared_ptr<AnyConnector> connector) = 0;
171 
176  virtual void setOutputConnector(std::shared_ptr<AnyConnector> connector) = 0;
177 
182  virtual void terminateConnections() = 0;
183 
188  virtual void gatherProfileData(std::map<AnyTaskManager *, TaskManagerProfile *> *taskManagerProfiles) = 0;
189 
194  virtual size_t getThreadsRemaining() = 0;
195 
199 
203  void printProfile() {
204  std::cout << "===================== " << this->getName() << " " << prefix() << " ===================" << std::endl;
205  std::cout << "COMPUTE TIME: " << getComputeTime() << " us WAIT TIME: " << getWaitTime() << " us" << std::endl;
206 
207  if (this->getInputConnector() != nullptr) {
208  std::cout << "Input connector: ";
209  this->getInputConnector()->profileConsume(this->getNumThreads(), true);
210  }
211 // if (this->getOutputConnector() != nullptr) {
212 // std::cout << "Output connector: ";
213 // this->getOutputConnector()->profileProduce(this->getNumThreads());
214 // }
215  this->getTaskFunction()->profileITask();
216  std::cout << "-------------------------- " << this->getName() << " (thread: " << this->getThreadId()
217  << ") -------------------------- " << std::endl << std::endl;
218 
219  this->getTaskFunction()->printProfile();
220 
221  }
222 
223 
224  // TODO: Delete or Add #ifdef
225 // /**
226 // * Sets the task graph communicator
227 // * @param communicator the task graph communicator
228 // */
229 // void setTaskGraphCommunicator(TaskGraphCommunicator *communicator) {
230 // this->taskGraphCommunicator = communicator;
231 // this->getTaskFunction()->setTaskGraphCommunicator(this->taskGraphCommunicator);
232 // }
233 //
234 // /**
235 // * Sends data packet along task graph communicator
236 // * @param packet the data packet to communicate
237 // */
238 // void sendDataPacket(std::shared_ptr<DataPacket> packet)
239 // {
240 // this->taskGraphCommunicator->produceDataPacket(packet);
241 // }
242 
249  void updateAddressAndPipelines(std::string address, size_t pipelineId, size_t numPipelines) {
250  this->numPipelines = numPipelines;
251  this->address = address;
252  this->pipelineId = pipelineId;
253  }
254 
260  std::string getAddress() {
261  return this->address;
262  }
263 
269  this->numPipelines = numPipelines;
270  this->getTaskFunction()->setNumPipelines(numPipelines);
271  }
272 
277  size_t getNumPipelines() { return this->numPipelines; }
278 
283  void setPipelineId(size_t id) {
284  this->pipelineId = id;
285  this->getTaskFunction()->setPipelineId(id);
286  }
287 
292  size_t getPipelineId() { return this->pipelineId; }
293 
298  size_t getNumThreads() const { return this->numThreads; }
299 
304  void setAlive(bool val) { this->alive = val; }
305 
312  bool isAlive() { return this->alive; }
313 
314 
319  void setInitialized(bool val) {this->initialized = val; }
320 
327  bool isInitialized() { return this->initialized; }
328 
335  void setStartTask(bool val) { this->startTask = val; }
336 
343  bool isStartTask() { return this->startTask; }
344 
351  bool isPoll() { return this->poll; }
352 
357  size_t getTimeout() { return this->timeout; }
358 
363  void incTaskComputeTime(int64_t val) { this->taskComputeTime += val; }
364 
369  void incWaitTime(int64_t val) { this->taskWaitTime += val; }
370 
374  void shutdown() {
375  HTGS_DEBUG("shutting down: " << this->prefix() << " " << this->getName() << std::endl);
376 #ifdef USE_NVTX
377  nvtxRangeId_t rangeId = this->nvtxProfiler->startRangeShuttingDown();
378 #endif
379  this->getTaskFunction()->shutdown();
380 
381 #ifdef USE_NVTX
382  this->nvtxProfiler->endRangeShuttingDown(rangeId);
383 #endif
384  }
385 
390  std::string getName() { return this->getTaskFunction()->getName(); }
391 
396  void debug() {
397  HTGS_DEBUG(prefix() << this->getName() << " input connector: " << getInputConnector() << " output connector: " <<
398  getOutputConnector() << " Details: " << std::endl);
399  this->getTaskFunction()->debug();
400  }
401 
406  std::string getNameWithPipelineId() { return this->getTaskFunction()->getNameWithPipelineId(); }
407 
411  std::string getDot(int flags) {
412  if ((flags & DOTGEN_FLAG_SHOW_ALL_THREADING) != 0) {
413  return this->getTaskFunction()->genDot(flags, this->getInputConnector(), this->getOutputConnector());
414  } else if (this->threadId == 0) {
415  return this->getTaskFunction()->genDot(flags, this->getInputConnector(), this->getOutputConnector());
416  } else {
417  return "";
418  }
419  }
420 
425  void setThreadId(size_t id) {
426  this->threadId = id;
427  }
428 
433  size_t getThreadId() {
434  return this->threadId;
435  }
442  unsigned long long int getComputeTime() {
443 #ifdef PROFILE
445 #else
446  return 0;
447 #endif
448  }
449 
454  unsigned long long int getExecuteTime() {
455 #ifdef PROFILE
456  return taskComputeTime;
457 #else
458  return 0;
459 #endif
460  }
461 
467  unsigned long long int getWaitTime() {
468 #ifdef PROFILE
469  return taskWaitTime;
470 #else
471  return 0;
472 #endif
473  }
474 
480  size_t getMaxQueueSize() {
481 #ifdef PROFILE
482  return this->getInputConnector() != nullptr ? this->getInputConnector()->getMaxQueueSize() : 0;
483 #else
484  return 0;
485 #endif
486  }
487 
491  void resetProfile() {
492  taskComputeTime = 0;
493  taskWaitTime = 0;
494  if (this->getInputConnector() != nullptr)
495  {
496  this->getInputConnector()->resetMaxQueueSize();
497  }
498 
499  }
500 
505  unsigned long long int getTaskComputeTime()
506  {
507  return taskComputeTime;
508  }
509 
511  std::string prefix() {
512  return std::string(
513  "Thread id: " + std::to_string(this->threadId) + " (out of " + std::to_string(this->numThreads)
514  + "); Pipeline id " + std::to_string(this->pipelineId) + " (out of " + std::to_string(this->numPipelines));
515  // TODO: Delete or Add #ifdef
516 // ") Address: " + this->getAddress());
517  }
518 
519 
520 #ifdef USE_NVTX
521  void setProfiler(NVTXProfiler *profiler) {
522  this->nvtxProfiler = profiler;
523  }
524  NVTXProfiler *getProfiler() const {
525  return nvtxProfiler;
526  }
527 
528  void releaseProfiler() {
529  delete nvtxProfiler;
530  nvtxProfiler = nullptr;
531  }
532 #endif
533 
535 
536  private:
537 
538  unsigned long long int taskComputeTime;
539  unsigned long long int taskWaitTime;
540 
541  size_t timeout;
542  bool poll;
543 
544  bool startTask;
545  bool alive;
546  bool initialized;
547 
548  size_t threadId;
549  size_t numThreads;
550 
551  size_t pipelineId;
552  size_t numPipelines;
553  std::string address;
554 
555  // TODO: Delete or Add #ifdef
556 // TaskGraphCommunicator *taskGraphCommunicator; //!< Task graph communicator
557 #ifdef USE_NVTX
558  NVTXProfiler *nvtxProfiler;
559 #endif
560 };
561 
574  public:
584  TaskManagerThread(size_t threadId, AnyTaskManager *task, std::shared_ptr<std::atomic_size_t> numThreads, std::condition_variable *taskGraphInitializeCond, std::mutex *taskGraphInitializeMutex) {
585  this->task = task;
586  this->terminated = false;
587  this->numThreads = numThreads;
588  this->task->setRuntimeThread(this);
589  this->task->setThreadId(threadId);
590  this->numThreadsAfterDecrement = *this->numThreads;
591  this->taskGraphInitializeCond = taskGraphInitializeCond;
592  this->taskGraphInitializeMutex = taskGraphInitializeMutex;
593  }
594 
599  HTGS_DEBUG_VERBOSE("TaskManagerThread: " << this << " is deleted");
600  }
601 
607  int run() {
608  // TODO: Remove?
609 //#ifdef USE_NVTX
610 // NVTXProfiler *profiler = new NVTXProfiler();
611 // task->setProfiler(profiler);
612 //#endif
613 
614  HTGS_DEBUG("Starting Thread for task : " << task->getName());
615  this->task->initialize();
616 
617  {
618  std::unique_lock<std::mutex> lock(*this->taskGraphInitializeMutex);
619  this->taskGraphInitializeCond->notify_all();
620  }
621 
622  while (!this->terminated) {
623  this->task->executeTask();
624  }
625  this->task->shutdown();
626 
627 
628  if (numThreadsAfterDecrement == 0)
629  {
630  this->task->terminateConnections();
631  }
632 
633 #ifdef USE_NVTX
634  if(hasNoThreadsRemaining())
635  {
636  this->task->releaseProfiler();
637  }
638 #endif
639 
640  return 0;
641  }
642 
647  size_t getThreadsRemaining() { return *this->numThreads; }
648 
653 
661  // Performs pre-decrement
662  size_t current = this->numThreads->fetch_sub(1) - 1;
663  numThreadsAfterDecrement = current;
664  return current == 0;
665  }
666 
673  bool hasNoThreadsRemaining() { return (*this->numThreads) == 0; }
674 
680  void terminate() { this->terminated = true; }
681 
682  private:
683  volatile bool terminated;
684  std::shared_ptr<std::atomic_size_t> numThreads;
686  size_t numThreadsAfterDecrement; // !< The number of threads after being decremented
687  std::condition_variable *taskGraphInitializeCond;
689 };
690 
691 }
692 
693 #endif //HTGS_ANYTASKMANAGER_HPP
virtual void terminateConnections()=0
Terminates all Connector edges.
virtual void executeTask()=0
Executes the TaskManager.
virtual AnyTaskManager * copy(bool deep)=0
Copies the TaskManager.
virtual std::string getName()=0
Virtual function to get the name of an ITask.
size_t getNumThreads() const
Gets the number of threads associated with this TaskManager.
Definition: AnyTaskManager.hpp:298
virtual void printProfile()=0
Prints the profile data to std::out.
virtual void debug()
Virtual function that is called to debug the ITask.
Definition: AnyITask.hpp:276
Implements the parent ITask, which removes the template arguments of an ITask.
Definition: AnyITask.hpp:48
std::string getNameWithPipelineId()
Gets the name of the ITask with it&#39;s pipeline ID.
Definition: AnyITask.hpp:509
volatile bool terminated
Whether the thread is ready to be terminated or not.
Definition: AnyTaskManager.hpp:683
size_t getThreadId()
Gets the thread id associated with the TaskManager.
Definition: AnyTaskManager.hpp:433
size_t getNumPipelines()
Gets the number of pipelines that this task manager belongs too.
Definition: AnyTaskManager.hpp:277
void shutdown()
Shuts down the TaskManager.
Definition: AnyTaskManager.hpp:374
NVTX Profiler uses NVIDIA&#39;s NVTX API to produce profiling metrics that are visualized with Nsight Sys...
virtual void setInputConnector(std::shared_ptr< AnyConnector > connector)=0
Sets the input BaseConnector.
size_t getThreadsRemaining()
Gets the number of threads remaining.
Definition: AnyTaskManager.hpp:647
AnyTaskManager * task
The TaskManager that is called from the thread.
Definition: AnyTaskManager.hpp:685
AnyTaskManager(size_t numThreads, bool isStartTask, size_t pipelineId, size_t numPipelines, std::string address)
Constructs an AnyTaskManager with an ITask as the task function and specific runtime parameters...
Definition: AnyTaskManager.hpp:56
std::string getAddress()
Gets the address of the task manager.
Definition: AnyTaskManager.hpp:260
unsigned long long int getExecuteTime()
Gets the total execution time for the task manager, including any waiting for memory within the execu...
Definition: AnyTaskManager.hpp:454
#define HTGS_DEBUG_VERBOSE(msg)
Prints a debug message to std:cerr with VERBOSE level.
Definition: debug_message.hpp:75
unsigned long long int getWaitTime()
Gets the wait time for the task manager.
Definition: AnyTaskManager.hpp:467
void profileITask()
Provides profile output for the ITask,.
Definition: AnyITask.hpp:482
bool startTask
Whether the task should start immediately.
Definition: AnyTaskManager.hpp:544
void incTaskComputeTime(int64_t val)
Increments the compute time profile value.
Definition: AnyTaskManager.hpp:363
std::string getDot(int flags)
Gets the dot notation for this TaskManager.
Definition: AnyTaskManager.hpp:411
int run()
Executes the task until the underlying Task has been terminated.
Definition: AnyTaskManager.hpp:607
void decrementNumThreadsRemaining()
Decrements the number of threads remaining by one.
Definition: AnyTaskManager.hpp:652
size_t getMaxQueueSize()
Gets the maximum size the input queue became during execution.
Definition: AnyTaskManager.hpp:480
void resetProfile()
Resets the profile data for this task.
Definition: AnyTaskManager.hpp:491
bool isInitialized()
Gets whether the TaskManager has initialized or not.
Definition: AnyTaskManager.hpp:327
unsigned long long int getTaskComputeTime()
Gets the task&#39;s compute time.
Definition: AnyTaskManager.hpp:505
virtual AnyITask * getTaskFunction()=0
Gets the ITask function associated with the TaskManager.
std::string getName()
Gets the name of the ITask.
Definition: AnyTaskManager.hpp:390
Implements parent ITask, removing template arguments.
unsigned long long int taskWaitTime
The total wait time for the task.
Definition: AnyTaskManager.hpp:539
size_t numPipelines
The number of execution pipelines.
Definition: AnyTaskManager.hpp:552
size_t getPipelineId()
Gets the pipeline identifer for this task from 0 to number of pipelines - 1.
Definition: AnyTaskManager.hpp:292
virtual ~AnyTaskManager()
Destructor.
Definition: AnyTaskManager.hpp:109
unsigned long long int getMemoryWaitTime() const
Gets the amount of time the task was waiting for memory.
Definition: AnyITask.hpp:566
bool isPoll()
Gets whether the task manager is polling for data or not.
Definition: AnyTaskManager.hpp:351
void debug()
Provides debug output.
Definition: AnyTaskManager.hpp:396
void incWaitTime(int64_t val)
Increments the wait time profile value.
Definition: AnyTaskManager.hpp:369
virtual void initialize()=0
Initializes the TaskManager.
unsigned long long int getComputeTime()
Gets the compute time for the task manager, removing the memory wait time.
Definition: AnyTaskManager.hpp:442
virtual std::string genDot(int flags, std::string dotId, std::shared_ptr< htgs::AnyConnector > input, std::shared_ptr< htgs::AnyConnector > output)
Virtual function that generates the input/output and per-task dot notation.
Definition: AnyITask.hpp:202
void updateAddressAndPipelines(std::string address, size_t pipelineId, size_t numPipelines)
Sets the task graph communicator.
Definition: AnyTaskManager.hpp:249
virtual std::shared_ptr< AnyConnector > getInputConnector()=0
Gets the input Connector.
void setStartTask(bool val)
Sets whether this task manager is a start task or not, which will immediately begin executing by send...
Definition: AnyTaskManager.hpp:335
std::string address
The address of the task graph this manager belongs too.
Definition: AnyTaskManager.hpp:553
virtual void shutdown()=0
Virtual function that is called when an ITask is being shutdown by it&#39;s owner thread.
bool isStartTask()
Gets whether this task manager will begin executing immediately with nullptr data or not...
Definition: AnyTaskManager.hpp:343
std::string getNameWithPipelineId()
Gets the name of the ITask with it&#39;s pipeline ID.
Definition: AnyTaskManager.hpp:406
bool initialized
Whether the task has been intitialized or not (called initialize function)
Definition: AnyTaskManager.hpp:546
void setNumPipelines(size_t numPipelines)
Sets the number of pipelines that this ITask belongs too.
Definition: AnyITask.hpp:378
The parent class for a Task that removes the template arguments.
Definition: AnyTaskManager.hpp:45
virtual void setOutputConnector(std::shared_ptr< AnyConnector > connector)=0
Sets the output BaseConnector.
~TaskManagerThread()
Destructor.
Definition: AnyTaskManager.hpp:598
bool isAlive()
Gets whether the TaskManager is alive or not.
Definition: AnyTaskManager.hpp:312
#define HTGS_DEBUG(msg)
Prints a debug message to std::cerr with standard level If DEBUG_FLAG is not defined, this equates to a no op Each message includes the file and line number for where the debug is called.
Definition: debug_message.hpp:65
void setAlive(bool val)
Sets the alive state for this task manager.
Definition: AnyTaskManager.hpp:304
TaskManagerThread(size_t threadId, AnyTaskManager *task, std::shared_ptr< std::atomic_size_t > numThreads, std::condition_variable *taskGraphInitializeCond, std::mutex *taskGraphInitializeMutex)
Constructs a TaskManagerThread with a specified AnyTaskManager and atomic number of threads that is s...
Definition: AnyTaskManager.hpp:584
std::mutex * taskGraphInitializeMutex
The mutex used to notify the task has been initialized.
Definition: AnyTaskManager.hpp:688
size_t getTimeout()
Gets the timeout period in microseconds for the task when the task is polling for data...
Definition: AnyTaskManager.hpp:357
AnyTaskManager(size_t numThreads, bool isStartTask, bool poll, size_t microTimeoutTime, size_t pipelineId, size_t numPipelines, std::string address)
Constructs an AnyTaskManager with an ITask as the task function and specific runtime parameters...
Definition: AnyTaskManager.hpp:81
void printProfile()
Prints the profiling data to std::cout.
Definition: AnyTaskManager.hpp:203
std::condition_variable * taskGraphInitializeCond
The condition variable that is used by the owner task graph for checking if all tasks have been initi...
Definition: AnyTaskManager.hpp:687
Defines common types used throughout the HTGS API and some of which that are used by users of HTGS su...
unsigned long long int taskComputeTime
The total compute time for the task.
Definition: AnyTaskManager.hpp:538
virtual void gatherProfileData(std::map< AnyTaskManager *, TaskManagerProfile *> *taskManagerProfiles)=0
Gathers profiling data for the TaskProfiler.
Manages a TaskManager that is bound to a thread for execution.
Definition: AnyTaskManager.hpp:573
bool decrementAndCheckNumThreadsRemaining()
Decrements the number of threads and checks if there are no threads remaining in a single operation...
Definition: AnyTaskManager.hpp:660
bool alive
Whether the task is still alive.
Definition: AnyTaskManager.hpp:545
bool poll
Whether the manager should poll for data.
Definition: AnyTaskManager.hpp:542
virtual void setRuntimeThread(TaskManagerThread *runtimeThread)=0
Sets the thread that is executing this TaskManager.
Implements the TaskManagerProfile class that is used to gather profile data for a task manager...
size_t numThreads
The number of threads spawned for the manager.
Definition: AnyTaskManager.hpp:549
size_t timeout
The timeout time for polling in microseconds.
Definition: AnyTaskManager.hpp:541
void setPipelineId(size_t pipelineId)
Sets the pipeline Id for this ITask.
Definition: AnyITask.hpp:359
#define DOTGEN_FLAG_SHOW_ALL_THREADING
Shows all threading fully expanded during dot generation.
Definition: TaskGraphDotGenFlags.hpp:26
virtual std::shared_ptr< AnyConnector > getOutputConnector()=0
Gets the output Connector.
Implements the task graph communicator task that communicates from each task to all other tasks in a ...
void setNumPipelines(size_t numPipelines)
Sets the number of pipelines associated with the TaskManager.
Definition: AnyTaskManager.hpp:268
void setInitialized(bool val)
Sets the initialized state for the task manager.
Definition: AnyTaskManager.hpp:319
virtual size_t getThreadsRemaining()=0
Gets the number of threads that are still running for the task.
void setPipelineId(size_t id)
Sets the pipeline Id associated with the TaskManager.
Definition: AnyTaskManager.hpp:283
size_t pipelineId
The execution pipeline id.
Definition: AnyTaskManager.hpp:551
size_t threadId
The thread id for the task (set after initialization)
Definition: AnyTaskManager.hpp:548
void setThreadId(size_t id)
Sets the thread id associated with the TaskManager.
Definition: AnyTaskManager.hpp:425
Definition: Bookkeeper.hpp:23
void terminate()
Indicates that the thread is ready to be terminated.
Definition: AnyTaskManager.hpp:680
bool hasNoThreadsRemaining()
Checks if there are no more threads executing a Task.
Definition: AnyTaskManager.hpp:673
std::shared_ptr< std::atomic_size_t > numThreads
The number of total threads managing the TaskManager.
Definition: AnyTaskManager.hpp:684