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 class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount {
60 PUBLISHED:
61  INLINE AsyncFuture();
62  virtual ~AsyncFuture();
63 
64  EXTENSION(static PyObject *__await__(PyObject *self));
65  EXTENSION(static PyObject *__iter__(PyObject *self));
66 
67  INLINE bool done() const;
68  INLINE bool cancelled() const;
69  EXTENSION(PyObject *result(PyObject *timeout = Py_None) const);
70 
71  virtual bool cancel();
72 
73  INLINE void set_done_event(const std::string &done_event);
74  INLINE const std::string &get_done_event() const;
75  MAKE_PROPERTY(done_event, get_done_event, set_done_event);
76 
77  EXTENSION(PyObject *add_done_callback(PyObject *self, PyObject *fn));
78 
79  EXTENSION(static PyObject *gather(PyObject *args));
80 
81  virtual void output(std::ostream &out) const;
82 
83  BLOCKING void wait();
84  BLOCKING void wait(double timeout);
85 
86  INLINE void set_result(std::nullptr_t);
87  INLINE void set_result(TypedObject *result);
88  INLINE void set_result(TypedReferenceCount *result);
89  INLINE void set_result(TypedWritableReferenceCount *result);
90  INLINE void set_result(const EventParameter &result);
91 
92 public:
93  void set_result(TypedObject *ptr, ReferenceCount *ref_ptr);
94 
95  INLINE TypedObject *get_result() const;
96  INLINE void get_result(TypedObject *&ptr, ReferenceCount *&ref_ptr) const;
97 
99  INLINE static AsyncFuture *gather(Futures futures);
100 
101  virtual bool is_task() const {return false;}
102 
103  void notify_done(bool clean_exit);
104  bool add_waiting_task(AsyncTask *task);
105 
106 private:
107  void wake_task(AsyncTask *task);
108 
109 protected:
110  enum FutureState {
111  // Pending states
112  FS_pending,
113  FS_locked_pending,
114 
115  // Done states
116  FS_finished,
117  FS_cancelled,
118  };
119  INLINE bool try_lock_pending();
120  INLINE void unlock(FutureState new_state = FS_pending);
121  INLINE bool set_future_state(FutureState state);
122 
123  AsyncTaskManager *_manager;
124  TypedObject *_result;
125  PT(ReferenceCount) _result_ref;
126  AtomicAdjust::Integer _future_state;
127 
128  std::string _done_event;
129 
130  // Tasks and gathering futures waiting for this one to complete.
131  Futures _waiting;
132 
133  friend class AsyncGatheringFuture;
134  friend class AsyncTaskChain;
135  friend class PythonTask;
136 
137 public:
138  static TypeHandle get_class_type() {
139  return _type_handle;
140  }
141  static void init_type() {
142  TypedReferenceCount::init_type();
143  register_type(_type_handle, "AsyncFuture",
144  TypedReferenceCount::get_class_type());
145  }
146  virtual TypeHandle get_type() const {
147  return get_class_type();
148  }
149  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
150 
151 private:
152  static TypeHandle _type_handle;
153 };
154 
155 INLINE std::ostream &operator << (std::ostream &out, const AsyncFuture &fut) {
156  fut.output(out);
157  return out;
158 };
159 
160 /**
161  * Specific future that collects the results of several futures.
162  */
163 class EXPCL_PANDA_EVENT AsyncGatheringFuture final : public AsyncFuture {
164 private:
166 
167 public:
168  virtual bool cancel() override;
169 
170  INLINE size_t get_num_futures() const;
171  INLINE AsyncFuture *get_future(size_t i) const;
172  INLINE TypedObject *get_result(size_t i) const;
173 
174 private:
175  const Futures _futures;
176  AtomicAdjust::Integer _num_pending;
177 
178  friend class AsyncFuture;
179 
180 public:
181  static TypeHandle get_class_type() {
182  return _type_handle;
183  }
184  static void init_type() {
185  AsyncFuture::init_type();
186  register_type(_type_handle, "AsyncGatheringFuture",
187  AsyncFuture::get_class_type());
188  }
189  virtual TypeHandle get_type() const override {
190  return get_class_type();
191  }
192  virtual TypeHandle force_init_type() override {init_type(); return get_class_type();}
193 
194 private:
195  static TypeHandle _type_handle;
196 };
197 
198 #include "asyncFuture.I"
199 
200 #endif
This class represents a thread-safe handle to a promised future result of an asynchronous operation...
Definition: asyncFuture.h:59
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(), along with zero to four record_derivation()s.
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&#39;s result.
Definition: asyncFuture.I:65
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:163
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.