Panda3D
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 
23 class AsyncTaskManager;
24 class AsyncTask;
25 class ConditionVarFull;
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  */
61 class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount {
62 PUBLISHED:
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  INLINE void set_result(std::nullptr_t);
89  INLINE void set_result(TypedObject *result);
90  INLINE void set_result(TypedReferenceCount *result);
91  INLINE void set_result(TypedWritableReferenceCount *result);
92  INLINE void set_result(const EventParameter &result);
93 
94 public:
95  void set_result(TypedObject *ptr, ReferenceCount *ref_ptr);
96 
97  INLINE TypedObject *get_result() const;
98  INLINE void get_result(TypedObject *&ptr, ReferenceCount *&ref_ptr) const;
99 
100  typedef pvector<PT(AsyncFuture)> Futures;
101  INLINE static AsyncFuture *gather(Futures futures);
102 
103  virtual bool is_task() const {return false;}
104 
105  void notify_done(bool clean_exit);
106  bool add_waiting_task(AsyncTask *task);
107 
108 private:
109  void wake_task(AsyncTask *task);
110 
111 protected:
112  enum FutureState {
113  // Pending states
114  FS_pending,
115  FS_locked_pending,
116 
117  // Done states
118  FS_finished,
119  FS_cancelled,
120  };
121  INLINE bool try_lock_pending();
122  INLINE void unlock(FutureState new_state = FS_pending);
123  INLINE bool set_future_state(FutureState state);
124 
125  AsyncTaskManager *_manager;
126  TypedObject *_result;
127  PT(ReferenceCount) _result_ref;
128  AtomicAdjust::Integer _future_state;
129 
130  std::string _done_event;
131 
132  // Tasks and gathering futures waiting for this one to complete.
133  Futures _waiting;
134 
135  friend class AsyncGatheringFuture;
136  friend class AsyncTaskChain;
137  friend class PythonTask;
138 
139 public:
140  static TypeHandle get_class_type() {
141  return _type_handle;
142  }
143  static void init_type() {
144  TypedReferenceCount::init_type();
145  register_type(_type_handle, "AsyncFuture",
146  TypedReferenceCount::get_class_type());
147  }
148  virtual TypeHandle get_type() const {
149  return get_class_type();
150  }
151  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
152 
153 private:
154  static TypeHandle _type_handle;
155 };
156 
157 INLINE std::ostream &operator << (std::ostream &out, const AsyncFuture &fut) {
158  fut.output(out);
159  return out;
160 };
161 
162 /**
163  * Specific future that collects the results of several futures.
164  */
165 class EXPCL_PANDA_EVENT AsyncGatheringFuture final : public AsyncFuture {
166 private:
168 
169 public:
170  virtual bool cancel() override;
171 
172  INLINE size_t get_num_futures() const;
173  INLINE AsyncFuture *get_future(size_t i) const;
174  INLINE TypedObject *get_result(size_t i) const;
175 
176 private:
177  const Futures _futures;
178  AtomicAdjust::Integer _num_pending;
179 
180  friend class AsyncFuture;
181 
182 public:
183  static TypeHandle get_class_type() {
184  return _type_handle;
185  }
186  static void init_type() {
187  AsyncFuture::init_type();
188  register_type(_type_handle, "AsyncGatheringFuture",
189  AsyncFuture::get_class_type());
190  }
191  virtual TypeHandle get_type() const override {
192  return get_class_type();
193  }
194  virtual TypeHandle force_init_type() override {init_type(); return get_class_type();}
195 
196 private:
197  static TypeHandle _type_handle;
198 };
199 
200 #include "asyncFuture.I"
201 
202 #endif
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
An optional parameter associated with an event.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedObject * get_result() const
Returns this future's result.
Definition: asyncFuture.I:65
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The AsyncTaskChain is a subset of the AsyncTaskManager.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Specific future that collects the results of several futures.
Definition: asyncFuture.h:165
A base class for all things that want to be reference-counted.
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.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual bool cancel()
Cancels the future.
Definition: asyncFuture.cxx:43
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.