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
AsyncTaskChain
The AsyncTaskChain is a subset of the AsyncTaskManager.
Definition: asyncTaskChain.h:50
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
eventParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandabase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ReferenceCount
A base class for all things that want to be reference-counted.
Definition: referenceCount.h:38
register_type
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
AsyncGatheringFuture
Specific future that collects the results of several futures.
Definition: asyncFuture.h:165
ConditionVarFull
This class implements a condition variable; see ConditionVar for a brief introduction to this class.
Definition: conditionVarFull.h:44
typedWritableReferenceCount.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedReferenceCount
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
Definition: typedReferenceCount.h:31
AsyncFuture
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
AsyncFuture::get_result
TypedObject * get_result() const
Returns this future's result.
Definition: asyncFuture.I:65
asyncFuture.I
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AsyncTask
This class represents a concrete task performed by an AsyncManager.
Definition: asyncTask.h:32
atomicAdjust.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AsyncTaskManager
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
Definition: asyncTaskManager.h:48
EventParameter
An optional parameter associated with an event.
Definition: eventParameter.h:35
AsyncFuture::cancel
virtual bool cancel()
Cancels the future.
Definition: asyncFuture.cxx:57
TypedWritableReferenceCount
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Definition: typedWritableReferenceCount.h:31
typedReferenceCount.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedObject
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88