HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
taskGraph.h
Go to the documentation of this file.
1 //
2 // Copyright 2025 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_WORK_TASK_GRAPH_H
8 #define PXR_BASE_WORK_TASK_GRAPH_H
9 
10 #include "pxr/pxr.h"
11 
12 #include "pxr/base/work/api.h"
14 #include "pxr/base/work/impl.h"
16 
17 #include <tbb/enumerable_thread_specific.h>
18 
19 #include <utility>
20 #include <vector>
21 
23 
24 /// Instances of this class are used to spawn and wait on a directed graph of
25 /// tasks, where tasks preserve a pointer to their parent task/successor and
26 /// a ref count to dynamically track pending children. It supports adding new
27 /// tasks during the execution of running tasks, continuation passing,
28 /// recycling of task resources, and scheduler bypass.
29 ///
30 /// This organization of tasks is suited for problems that exhibit hierarchical
31 /// structured parallelism: tasks that discover additional work during their
32 /// execution. If these optimizations are not required, consider a higher-level
33 /// abstraction, e.g. WorkParallelForEach or direct submission of work via
34 /// WorkDispatcher.
35 ///
37 {
38 private:
39  // Select underlying implementation.
40 #if defined WORK_IMPL_HAS_TASK_GRAPH
41  using _Impl = PXR_WORK_IMPL_NS::WorkImpl_TaskGraph;
42 #else
44 #endif
45 
46 public:
47  WorkTaskGraph() = default;
48  ~WorkTaskGraph() noexcept = default;
49 
50  WorkTaskGraph(WorkTaskGraph const &) = delete;
51  WorkTaskGraph &operator=(WorkTaskGraph const &) = delete;
52 
53  /// Base class for parallel tasks.
54  class BaseTask;
55 
56  /// Container for allocated tasks to be spawned.
57  using TaskList = std::vector<BaseTask *>;
58 
59  /// Thread-local storage for allocated tasks to be spawned.
60  using TaskLists = tbb::enumerable_thread_specific<TaskList>;
61 
62  /// Allocate and construct a new top-level task to run with RunTask() or
63  /// RunLists().
64  ///
65  /// The caller owns the returned task until it is passed to RunTask() or
66  /// RunLists().
67  template <typename F, typename ... Args>
68  F * AllocateTask(Args&&... args) {
69  return _impl.AllocateTask<F>(std::forward<Args>(args)...);
70  }
71 
72  /// Submit a concurrent task for execution.
73  ///
74  /// Transfers ownership of \p task to this task graph instance.
75  template <typename F>
76  inline void RunTask(F * task) {
77  _impl.RunTask(task);
78  }
79 
80  /// Submit concurrent tasks accumulated in thread-local lists for
81  /// execution.
82  ///
83  /// Transfers ownership of all the tasks in the \p taskLists to this task
84  /// graph instance.
85  WORK_API void RunLists(const TaskLists &taskLists);
86 
87  /// Wait on all the running tasks to complete.
88  inline void Wait() {
89  _impl.Wait();
90  }
91 
92 private:
93  _Impl _impl;
94 };
95 
96 /// Base class for a parallel task that emulates tbb::task (deprecated in the
97 /// oneTBB version upgrade.) This task abstracts a block of concurrent work
98 /// by exploiting knowledge of TBB's task-based work stealing scheduler
99 /// architecture to provide memory and runtime optimizations.
100 ///
101 /// This is a callable object that can serve as an anchor to dynamically spawn
102 /// additional children. It supports continuation passing, recycling of task
103 /// resources, and scheduler bypass. All task graph tasks are heap-allocated
104 /// and automatically released/reclaimed using reference counting.
105 ///
107 private:
109 
110 public:
111  BaseTask() = default;
112  WORK_API virtual ~BaseTask();
113 
114  /// Derived classes override this method to implement a parallel unit of
115  /// work.
116  virtual BaseTask * execute() = 0;
117 
118  /// Increment the reference count of child tasks that must complete before
119  /// this task can proceed.
122  }
123 
124  /// Decrement the reference count of child tasks that must complete before
125  /// this task can proceed.
128  }
129 
130  /// Construct a new subtask and increment the reference count of the
131  /// calling task.
132  template <typename F, typename ... Args>
133  F * AllocateChild(Args&&... args) {
134  return _Base::AllocateChild<F>(std::forward<Args>(args)...);
135  }
136 
137 protected:
138  /// Recycles this as a continuation task to mitigate the allocation
139  /// overhead of the continuation task.
140  ///
141  /// \note Note that the task graph performs safe continuation passing by
142  /// default, i.e. it assumes an extra increment of the child reference
143  /// count to handle the case when the continued task returns before a
144  /// longer-lived child task. In this case, the extra reference prevents
145  /// the continuation task from executing prematurely and orphaning its
146  /// running child task.
149  }
150 
151 };
152 
153 
155 
156 #endif
virtual BaseTask * execute()=0
WORK_API void RunLists(const TaskLists &taskLists)
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
F * AllocateTask(Args &&...args)
WorkTaskGraph & operator=(WorkTaskGraph const &)=delete
#define WORK_API
Definition: api.h:23
void RunTask(F *task)
Definition: taskGraph.h:76
void Wait()
Wait on all the running tasks to complete.
Definition: taskGraph.h:88
WorkTaskGraph()=default
virtual WORK_API ~BaseTask()
F * AllocateTask(Args &&...args)
Definition: taskGraph.h:68
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
**If you just want to fire and args
Definition: thread.h:618
F * AllocateChild(Args &&...args)
Definition: taskGraph.h:133
std::vector< BaseTask * > TaskList
Container for allocated tasks to be spawned.
Definition: taskGraph.h:57
~WorkTaskGraph() noexcept=default
tbb::enumerable_thread_specific< TaskList > TaskLists
Thread-local storage for allocated tasks to be spawned.
Definition: taskGraph.h:60