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:
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
Specific future that collects the results of several futures.
The AsyncTaskChain is a subset of the AsyncTaskManager.
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.
A base class for all things that want to be reference-counted.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition typedObject.h:88
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
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.