Panda3D
Loading...
Searching...
No Matches
asyncFuture.h
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file asyncFuture.h
10 * @author rdb
11 * @date 2017-11-28
12 */
13
14#ifndef ASYNCFUTURE_H
15#define ASYNCFUTURE_H
16
17#include "pandabase.h"
18#include "typedReferenceCount.h"
20#include "eventParameter.h"
21#include "atomicAdjust.h"
22
24class AsyncTask;
26
27/**
28 * This class represents a thread-safe handle to a promised future result of
29 * an asynchronous operation, providing methods to query its status and result
30 * as well as register callbacks for this future's completion.
31 *
32 * An AsyncFuture can be awaited from within a coroutine or task. It keeps
33 * track of tasks waiting for this future and automatically reactivates them
34 * upon this future's completion.
35 *
36 * A task itself is also a subclass of AsyncFuture. Other subclasses are
37 * not generally necessary, except to override the function of `cancel()`.
38 *
39 * Until the future is done, it is "owned" by the resolver thread, though it's
40 * still legal for other threads to query its state. When the resolver thread
41 * resolves this future using `set_result()`, or any thread calls `cancel()`,
42 * it instantly enters the "done" state, after which the result becomes a
43 * read-only field that all threads can access.
44 *
45 * When the future returns true for done(), a thread can use cancelled() to
46 * determine whether the future was cancelled or get_result() to access the
47 * result of the operation. Not all operations define a meaningful result
48 * value, so some will always return nullptr.
49 *
50 * In Python, the `cancelled()`, `wait()` and `get_result()` methods are
51 * wrapped up into a single `result()` method which waits for the future to
52 * complete before either returning the result or throwing an exception if the
53 * future was cancelled.
54 * However, it is preferable to use the `await` keyword when running from a
55 * coroutine, which only suspends the current task and not the entire thread.
56 *
57 * This API aims to mirror and be compatible with Python's Future class.
58 *
59 * @since 1.10.0
60 */
61class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount {
62PUBLISHED:
63 INLINE AsyncFuture();
64 virtual ~AsyncFuture();
65
66 EXTENSION(static PyObject *__await__(PyObject *self));
67 EXTENSION(static PyObject *__iter__(PyObject *self));
68
69 INLINE bool done() const;
70 INLINE bool cancelled() const;
71 EXTENSION(PyObject *result(PyObject *timeout = Py_None) const);
72
73 virtual bool cancel();
74
75 INLINE void set_done_event(const std::string &done_event);
76 INLINE const std::string &get_done_event() const;
77 MAKE_PROPERTY(done_event, get_done_event, set_done_event);
78
79 EXTENSION(PyObject *add_done_callback(PyObject *self, PyObject *fn));
80
81 EXTENSION(static PyObject *gather(PyObject *args));
82
83 virtual void output(std::ostream &out) const;
84
85 BLOCKING void wait();
86 BLOCKING void wait(double timeout);
87
88 EXTENSION(void set_result(PyObject *));
89
90public:
91 INLINE void set_result(std::nullptr_t);
92 INLINE void set_result(TypedObject *result);
93 INLINE void set_result(TypedReferenceCount *result);
94 INLINE void set_result(TypedWritableReferenceCount *result);
95 INLINE void set_result(const EventParameter &result);
96 void set_result(TypedObject *ptr, ReferenceCount *ref_ptr);
97
98 INLINE TypedObject *get_result() const;
99 INLINE void get_result(TypedObject *&ptr, ReferenceCount *&ref_ptr) const;
100
101 typedef pvector<PT(AsyncFuture)> Futures;
102 INLINE static AsyncFuture *gather(Futures futures);
103
104 virtual bool is_task() const {return false;}
105
106 void notify_done(bool clean_exit);
107 bool add_waiting_task(AsyncTask *task);
108
109private:
110 void wake_task(AsyncTask *task);
111
112protected:
113 enum FutureState {
114 // Pending states
115 FS_pending,
116 FS_locked_pending,
117
118 // Done states
119 FS_finished,
120 FS_cancelled,
121 };
122 INLINE bool try_lock_pending();
123 INLINE void unlock(FutureState new_state = FS_pending);
124 INLINE bool set_future_state(FutureState state);
125
126 AsyncTaskManager *_manager;
127 TypedObject *_result;
128 PT(ReferenceCount) _result_ref;
129 AtomicAdjust::Integer _future_state;
130
131 std::string _done_event;
132
133 // Tasks and gathering futures waiting for this one to complete.
134 Futures _waiting;
135
136 friend class AsyncGatheringFuture;
137 friend class AsyncTaskChain;
138 friend class PythonTask;
139
140public:
141 static TypeHandle get_class_type() {
142 return _type_handle;
143 }
144 static void init_type() {
145 TypedReferenceCount::init_type();
146 register_type(_type_handle, "AsyncFuture",
147 TypedReferenceCount::get_class_type());
148 }
149 virtual TypeHandle get_type() const {
150 return get_class_type();
151 }
152 virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
153
154private:
155 static TypeHandle _type_handle;
156};
157
158INLINE std::ostream &operator << (std::ostream &out, const AsyncFuture &fut) {
159 fut.output(out);
160 return out;
161};
162
163/**
164 * Specific future that collects the results of several futures.
165 */
166class EXPCL_PANDA_EVENT AsyncGatheringFuture final : public AsyncFuture {
167private:
168 AsyncGatheringFuture(AsyncFuture::Futures futures);
169
170public:
171 virtual bool cancel() override;
172
173 INLINE size_t get_num_futures() const;
174 INLINE AsyncFuture *get_future(size_t i) const;
175 INLINE TypedObject *get_result(size_t i) const;
176
177private:
178 const Futures _futures;
179 AtomicAdjust::Integer _num_pending;
180
181 friend class AsyncFuture;
182
183public:
184 static TypeHandle get_class_type() {
185 return _type_handle;
186 }
187 static void init_type() {
188 AsyncFuture::init_type();
189 register_type(_type_handle, "AsyncGatheringFuture",
190 AsyncFuture::get_class_type());
191 }
192 virtual TypeHandle get_type() const override {
193 return get_class_type();
194 }
195 virtual TypeHandle force_init_type() override {init_type(); return get_class_type();}
196
197private:
198 static TypeHandle _type_handle;
199};
200
201#include "asyncFuture.I"
202
203#endif
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition asyncFuture.h:61
virtual bool cancel()
Cancels the future.
bool cancelled() const
Returns true if the future was cancelled.
Definition asyncFuture.I:37
void set_result(std::nullptr_t)
Sets this future's result.
Definition asyncFuture.I:92
void wait()
Waits until the future is done.
set_done_event
Sets the event name that will be triggered when the future finishes.
Definition asyncFuture.h:77
AsyncFuture()
Initializes the future in the pending state.
Definition asyncFuture.I:18
get_done_event
Returns the event name that will be triggered when the future finishes.
Definition asyncFuture.h:77
TypedObject * get_result() const
Returns this future's result.
Definition asyncFuture.I:65
static AsyncFuture * gather(Futures futures)
Creates a new future that returns `done()` when all of the contained futures are done.
bool done() const
Returns true if the future is done or has been cancelled.
Definition asyncFuture.I:29
TypedObject * get_result(size_t i) const
Returns the result of the nth future that was passed into the constructor.
size_t get_num_futures() const
Returns the number of futures that were passed to the constructor.
AsyncFuture * get_future(size_t i) const
Returns the nth future that was passed into the constructor.
virtual bool cancel() override
Cancels all the futures.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
This class represents a concrete task performed by an AsyncManager.
Definition asyncTask.h:32
This class implements a condition variable; see ConditionVar for a brief introduction to this class.
An optional parameter associated with an event.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.