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  EXTENSION(void set_result(PyObject *));
89 
90 public:
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 
109 private:
110  void wake_task(AsyncTask *task);
111 
112 protected:
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 
140 public:
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 
154 private:
155  static TypeHandle _type_handle;
156 };
157 
158 INLINE 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  */
166 class EXPCL_PANDA_EVENT AsyncGatheringFuture final : public AsyncFuture {
167 private:
169 
170 public:
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 
177 private:
178  const Futures _futures;
179  AtomicAdjust::Integer _num_pending;
180 
181  friend class AsyncFuture;
182 
183 public:
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 
197 private:
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.
Definition: asyncFuture.h:166
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(),...
Definition: register_type.I:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.