HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
parallelTaskSync.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_EXEC_VDF_PARALLEL_TASK_SYNC_H
8 #define PXR_EXEC_VDF_PARALLEL_TASK_SYNC_H
9 
10 ///\file
11 
12 #include "pxr/pxr.h"
13 
14 #include "pxr/exec/vdf/api.h"
16 
18 
19 #include <atomic>
20 #include <cstdint>
21 #include <memory>
22 
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 ///
27 /// \class VdfParallelTaskSync
28 ///
29 /// \brief Instances of this class are used to synchronize dynamic, acyclic
30 /// task graphs, allowing tasks to claim dependents for processing.
31 /// Methods on this class are thread-safe unless specifically called out
32 /// to not be thread-safe.
33 ///
35 {
36 public:
37  /// Noncopyable.
38  ///
39  VdfParallelTaskSync(const VdfParallelTaskSync &) = delete;
41 
42  /// Constructor.
43  ///
45  : _waitlists(1000)
46  , _num(0)
47  , _taskGraph(taskGraph)
48  {}
49 
50  /// Resets the state of all tasks in the graph. Ensures that \p num
51  /// entries are available for use.
52  ///
53  /// It is not thread-safe to call this method on the same instance from
54  /// multiple threads.
55  ///
56  VDF_API
57  void Reset(const size_t num);
58 
59  /// The different states a task can be in.
60  ///
61  enum class State {
62  Done, /// The task is already done.
63 
64  Wait, /// The task is currently running, the claimant must wait
65  /// for the task to complete.
66 
67  Claimed /// The task has been successfully claimed. The claimant
68  /// can go ahead and process the task.
69  };
70 
71  /// Claims the task \p idx for processing, and returns the new task state.
72  ///
73  /// This method will automatically increment the reference count of the
74  /// \p successor, if the task has already been claimed, and will cause
75  /// the reference count of \p successor to be automatically decremented as
76  /// soon as the task completes.
77  ///
78  inline State Claim(const size_t idx, WorkTaskGraph::BaseTask *successor);
79 
80  /// Mark the task \p idx as done.
81  ///
82  /// This method will notify any tasks depending on \p idx about the
83  /// completion of \p idx.
84  ///
85  inline void MarkDone(const size_t idx);
86 
87 private:
88 
89  // The different states a task can be in.
90  enum _TaskState : uint8_t {
91  _TaskStateUnclaimed,
92  _TaskStateClaimed,
93  _TaskStateDone
94  };
95 
96  // A byte-array indicating the state of each task.
97  std::unique_ptr<std::atomic<uint8_t>[]> _state;
98 
99  // A pointer to the waiting queue head for each task.
100  std::unique_ptr<VdfParallelTaskWaitlist::HeadPtr[]> _waiting;
101 
102  // The waitlist instance for managing the queues.
103  VdfParallelTaskWaitlist _waitlists;
104 
105  // The number of tasks in this graph.
106  size_t _num;
107 
108  // The task graph for running pending tasks.
109  WorkTaskGraph *_taskGraph;
110 
111 };
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 
117 {
118  // Get the current task state.
119  uint8_t state = _state[idx].load(std::memory_order_acquire);
120 
121  // If the task has completed, bail out.
122  if (state == _TaskStateDone) {
123  return State::Done;
124  }
125 
126  // If the task has not been claimed, yet, attempt to atomically claim it
127  // now. Return if this succeeds.
128  else if (state == _TaskStateUnclaimed &&
129  _state[idx].compare_exchange_strong(state, _TaskStateClaimed)) {
130  return State::Claimed;
131  }
132 
133  // If we have to wait, try to enqueue in the waiting list, but bail
134  // out if the task completes while attempting to do so.
135  return _waitlists.WaitOn(&_waiting[idx], successor)
136  ? State::Wait
137  : State::Done;
138 }
139 
140 void
142 {
143  // Mark the task done in the state array.
144  _state[idx].store(_TaskStateDone, std::memory_order_release);
145 
146  // Close the corresponding wait list and notify all waiting tasks.
147  _waitlists.CloseAndNotify(&_waiting[idx], _taskGraph);
148 }
149 
151 
152 #endif
VdfParallelTaskSync(const VdfParallelTaskSync &)=delete
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
State Claim(const size_t idx, WorkTaskGraph::BaseTask *successor)
#define VDF_API
Definition: api.h:25
VdfParallelTaskSync(WorkTaskGraph *taskGraph)
The task is already done.
VdfParallelTaskSync & operator=(const VdfParallelTaskSync &)=delete
void MarkDone(const size_t idx)
VDF_API bool WaitOn(HeadPtr *headPtr, WorkTaskGraph::BaseTask *successor)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
VDF_API bool CloseAndNotify(HeadPtr *headPtr, WorkTaskGraph *taskGraph)
VDF_API void Reset(const size_t num)
state
Definition: core.h:2289
Instances of this class are used to synchronize dynamic, acyclic task graphs, allowing tasks to claim...