| Taskflow: A General-purpose Task-parallel Programming System

Loading...
Searching...
No Matches
async_task.hpp
1#pragma once
2
3#include "graph.hpp"
4
10 namespace tf {
11
12// ----------------------------------------------------------------------------
13// AsyncTask
14// ----------------------------------------------------------------------------
15
45 class AsyncTask {
46
47 friend class Executor;
48
49 public:
50
54 AsyncTask() = default;
55
59 ~AsyncTask();
60
64 AsyncTask(const AsyncTask& rhs);
65
69 AsyncTask(AsyncTask&& rhs);
70
77 AsyncTask& operator = (const AsyncTask& rhs);
78
84 AsyncTask& operator = (AsyncTask&& rhs);
85
97 bool empty() const;
98
112 void reset();
113
122 size_t hash_value() const;
123
137 size_t use_count() const;
138
157 bool is_done() const;
158
178 std::exception_ptr exception_ptr() const;
179
185 bool has_exception_ptr() const;
186
187 private:
188
189 explicit AsyncTask(Node*);
190
191 Node* _node {nullptr};
192
193 void _incref();
194 void _decref();
195};
196
197// Constructor
198 inline AsyncTask::AsyncTask(Node* ptr) : _node{ptr} {
199 _incref();
200}
201
202// Function: _incref
203 inline void AsyncTask::_incref() {
204 if(_node) {
205 // increment the refcount packed in the lower 24 bits of _estate —
206 // no std::get_if needed since we know this node is DependentAsync
207 _node->_estate.fetch_add(ESTATE::REFCOUNT_ONE, std::memory_order_relaxed);
208 }
209}
210
211// Function: _decref
212 inline void AsyncTask::_decref() {
213 if(_node) {
214 // decrement the refcount packed in the lower 24 bits of _estate.
215 // mask out the state bits before comparing so we only check the refcount.
216 // if it reaches zero, no owners remain and we recycle the node.
217 if((_node->_estate.fetch_sub(ESTATE::REFCOUNT_ONE, std::memory_order_acq_rel)
218 & ESTATE::REFCOUNT_MASK) == ESTATE::REFCOUNT_ONE) {
219 recycle(_node);
220 }
221 }
222}
223
224// Copy Constructor
225 inline AsyncTask::AsyncTask(const AsyncTask& rhs) :
226 _node{rhs._node} {
227 _incref();
228}
229
230// Move Constructor
231 inline AsyncTask::AsyncTask(AsyncTask&& rhs) :
232 _node {rhs._node} {
233 rhs._node = nullptr;
234}
235
236// Destructor
237 inline AsyncTask::~AsyncTask() {
238 _decref();
239}
240
241// Copy assignment
242 inline AsyncTask& AsyncTask::operator = (const AsyncTask& rhs) {
243 _decref();
244 _node = rhs._node;
245 _incref();
246 return *this;
247}
248
249// Move assignment
250 inline AsyncTask& AsyncTask::operator = (AsyncTask&& rhs) {
251 _decref();
252 _node = rhs._node;
253 rhs._node = nullptr;
254 return *this;
255}
256
257// Function: exception
258 inline std::exception_ptr AsyncTask::exception_ptr() const {
259 return _node ? _node->_exception_ptr : nullptr;
260}
261
262// Function: has_exception
263 inline bool AsyncTask::has_exception_ptr() const {
264 return _node ? (_node->_exception_ptr != nullptr) : false;
265}
266
267// Function: empty
268 inline bool AsyncTask::empty() const {
269 return _node == nullptr;
270}
271
272// Function: reset
273 inline void AsyncTask::reset() {
274 _decref();
275 _node = nullptr;
276}
277
278// Function: hash_value
279 inline size_t AsyncTask::hash_value() const {
280 return std::hash<Node*>{}(_node);
281}
282
283// Function: use_count
284 inline size_t AsyncTask::use_count() const {
285 return _node == nullptr ? size_t{0} :
286 static_cast<size_t>(
287 _node->_estate.load(std::memory_order_relaxed) & ESTATE::REFCOUNT_MASK
288 );
289}
290
291// Function: is_done
292 inline bool AsyncTask::is_done() const {
293 return _node == nullptr ? true: (_node->_estate.load(std::memory_order_acquire) & ESTATE::FINISHED);
294}
295
296// ----------------------------------------------------------------------------
297// AsyncTaskHandleLike
298// ----------------------------------------------------------------------------
299
300
313 template <typename T>
314 concept AsyncTaskHandleLike = std::is_same_v<std::decay_t<T>, AsyncTask>;
315
316
317} // end of namespace tf ----------------------------------------------------
tf::AsyncTask
class to hold a dependent asynchronous task with shared ownership
Definition async_task.hpp:45
tf::AsyncTask::~AsyncTask
~AsyncTask()
destroys the managed dependent-async task if this is the last owner
Definition async_task.hpp:237
tf::AsyncTask::operator=
AsyncTask & operator=(const AsyncTask &rhs)
copy-assigns the dependent-async task from rhs
Definition async_task.hpp:242
tf::AsyncTask::AsyncTask
AsyncTask()=default
constructs an empty task handle
tf::AsyncTask::use_count
size_t use_count() const
returns the number of shared owners that are currently managing this dependent-async task
Definition async_task.hpp:284
tf::AsyncTask::reset
void reset()
release the managed object of this
Definition async_task.hpp:273
tf::AsyncTask::has_exception_ptr
bool has_exception_ptr() const
queries if the task has an exception pointer
Definition async_task.hpp:263
tf::AsyncTask::hash_value
size_t hash_value() const
obtains the hashed value of this dependent-async task
Definition async_task.hpp:279
tf::AsyncTask::exception_ptr
std::exception_ptr exception_ptr() const
retrieves the exception pointer of this task
Definition async_task.hpp:258
tf::AsyncTask::empty
bool empty() const
checks if this dependent-async task is associated with any task
Definition async_task.hpp:268
tf::AsyncTask::is_done
bool is_done() const
checks if this dependent-async task finishes
Definition async_task.hpp:292
tf::Executor
class to create an executor
Definition executor.hpp:62
tf::AsyncTaskHandleLike
concept to check if a type is a tf::AsyncTask
Definition async_task.hpp:314
tf
taskflow namespace
Definition small_vector.hpp:20