Panda3D
asyncFuture.I
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.I
10  * @author rdb
11  * @date 2017-11-28
12  */
13 
14 /**
15  * Initializes the future in the pending state.
16  */
18 AsyncFuture() :
19  _manager(nullptr),
20  _result(nullptr),
21  _future_state(FS_pending) {
22 }
23 
24 /**
25  * Returns true if the future is done or has been cancelled. It is always
26  * safe to call this.
27  */
28 INLINE bool AsyncFuture::
29 done() const {
30  return (FutureState)AtomicAdjust::get(_future_state) >= FS_finished;
31 }
32 
33 /**
34  * Returns true if the future was cancelled. It is always safe to call this.
35  */
36 INLINE bool AsyncFuture::
37 cancelled() const {
38  return (FutureState)AtomicAdjust::get(_future_state) == FS_cancelled;
39 }
40 
41 /**
42  * Sets the event name that will be triggered when the future finishes. Will
43  * not be triggered if the future is cancelled, but it will be triggered for
44  * a coroutine task that exits with an exception.
45  */
46 INLINE void AsyncFuture::
47 set_done_event(const std::string &done_event) {
48  nassertv(!done());
49  _done_event = done_event;
50 }
51 
52 /**
53  * Returns the event name that will be triggered when the future finishes.
54  * See set_done_event().
55  */
56 INLINE const std::string &AsyncFuture::
57 get_done_event() const {
58  return _done_event;
59 }
60 
61 /**
62  * Returns this future's result. Can only be called if done() returns true.
63  */
65 get_result() const {
66  // This is thread safe, since _result may no longer be modified after the
67  // state is changed to "done".
68  nassertr_always(done(), nullptr);
69  return _result;
70 }
71 
72 /**
73  * Returns this future's result as a pair of TypedObject, ReferenceCount
74  * pointers. Can only be called if done() returns true.
75  */
76 INLINE void AsyncFuture::
77 get_result(TypedObject *&ptr, ReferenceCount *&ref_ptr) const {
78  // This is thread safe, since _result may no longer be modified after the
79  // state is changed to "done".
80  nassertd(done()) {
81  ptr = nullptr;
82  ref_ptr = nullptr;
83  }
84  ptr = _result;
85  ref_ptr = _result_ref.p();
86 }
87 
88 /**
89  * Sets this future's result. Can only be called if done() returns false.
90  */
91 INLINE void AsyncFuture::
92 set_result(std::nullptr_t) {
93  set_result(nullptr, nullptr);
94 }
95 
96 INLINE void AsyncFuture::
97 set_result(TypedObject *result) {
98  set_result(result, nullptr);
99 }
100 
101 INLINE void AsyncFuture::
103  set_result(result, result);
104 }
105 
106 INLINE void AsyncFuture::
108  set_result(result, result);
109 }
110 
111 INLINE void AsyncFuture::
112 set_result(const EventParameter &result) {
113  set_result(result.get_ptr(), result.get_ptr());
114 }
115 
116 /**
117  * Creates a new future that returns `done()` when all of the contained
118  * futures are done.
119  *
120  * Calling `cancel()` on the returned future will result in all contained
121  * futures that have not yet finished to be cancelled.
122  */
124 gather(Futures futures) {
125  if (futures.empty()) {
126  AsyncFuture *fut = new AsyncFuture;
127  fut->_future_state = (AtomicAdjust::Integer)FS_finished;
128  return fut;
129  } else if (futures.size() == 1) {
130  return futures[0].p();
131  } else {
132  return (AsyncFuture *)new AsyncGatheringFuture(std::move(futures));
133  }
134 }
135 
136 /**
137  * Tries to atomically lock the future, assuming it is pending. Returns false
138  * if it is not in the pending state, implying it's either done or about to be
139  * cancelled.
140  */
141 INLINE bool AsyncFuture::
142 try_lock_pending() {
143  return set_future_state(FS_locked_pending);
144 }
145 
146 /**
147  * Should be called after try_lock_pending() returns true.
148  */
149 INLINE void AsyncFuture::
150 unlock(FutureState new_state) {
151  nassertv(new_state != FS_locked_pending);
152  FutureState orig_state = (FutureState)AtomicAdjust::set(_future_state, (AtomicAdjust::Integer)new_state);
153  nassertv(orig_state == FS_locked_pending);
154 }
155 
156 /**
157  * Atomically changes the future state from pending to another state. Returns
158  * true if successful, false if the future was already done.
159  * Note that once a future is in a "done" state (ie. cancelled or finished) it
160  * can never change state again.
161  */
162 INLINE bool AsyncFuture::
163 set_future_state(FutureState state) {
164  FutureState orig_state = (FutureState)
166  _future_state,
167  (AtomicAdjust::Integer)FS_pending,
168  (AtomicAdjust::Integer)state);
169 
170  while (orig_state == FS_locked_pending) {
172  orig_state = (FutureState)AtomicAdjust::compare_and_exchange(
173  _future_state,
174  (AtomicAdjust::Integer)FS_pending,
175  (AtomicAdjust::Integer)state);
176  }
177 
178  return orig_state == FS_pending;
179 }
180 
181 /**
182  * Returns the number of futures that were passed to the constructor.
183  */
185 get_num_futures() const {
186  return _futures.size();
187 }
188 
189 /**
190  * Returns the nth future that was passed into the constructor.
191  */
193 get_future(size_t i) const {
194  nassertr(i < _futures.size(), nullptr);
195  return _futures[i].p();
196 }
197 
198 /**
199  * Returns the result of the nth future that was passed into the constructor.
200  */
202 get_result(size_t i) const {
203  nassertr(i < _futures.size(), nullptr);
204  return _futures[i]->get_result();
205 }
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
bool cancelled() const
Returns true if the future was cancelled.
Definition: asyncFuture.I:37
void set_result(std::nullptr_t)
Sets this future's result.
Definition: asyncFuture.I:92
set_done_event
Sets the event name that will be triggered when the future finishes.
Definition: asyncFuture.h:77
AsyncFuture()
Initializes the future in the pending state.
Definition: asyncFuture.I:18
get_done_event
Returns the event name that will be triggered when the future finishes.
Definition: asyncFuture.h:77
TypedObject * get_result() const
Returns this future's result.
Definition: asyncFuture.I:65
static AsyncFuture * gather(Futures futures)
Creates a new future that returns `done()` when all of the contained futures are done.
Definition: asyncFuture.I:124
bool done() const
Returns true if the future is done or has been cancelled.
Definition: asyncFuture.I:29
Specific future that collects the results of several futures.
Definition: asyncFuture.h:166
size_t get_num_futures() const
Returns the number of futures that were passed to the constructor.
Definition: asyncFuture.I:185
AsyncFuture * get_future(size_t i) const
Returns the nth future that was passed into the constructor.
Definition: asyncFuture.I:193
static Integer set(Integer &var, Integer new_value)
Atomically changes the indicated variable and returns the original value.
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
An optional parameter associated with an event.
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
A base class for all things that want to be reference-counted.
static void force_yield()
Suspends the current thread for the rest of the current epoch.
Definition: thread.I:201
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.