AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
AFuture< T > Class Template Referencefinal

Represents a value that will be available at some point in the future. More...

Detailed Description

template<typename T = void>
class AFuture< T >

Represents a value that will be available at some point in the future.

Template Parameters
Tresult type (void is default)

AFuture is used as a result for asynchronous functions.

AFuture is returned by async keyword:

AFuture<int> theFuture = async {
AThread::sleep(1000); // long operation
return 123;
};
...
cout << *theFuture; // waits for the task, outputs 123
Represents a value that will be available at some point in the future.
Definition: AFuture.h:620
static void sleep(std::chrono::milliseconds duration)
Sleep for specified duration. Most operation systems guarantee that elasped time will be greater than...
Definition: AThread.cpp:207
#define async
Executes following {} block asynchronously in the global thread pool. Unlike asyncX,...
Definition: kAUI.h:329

If your operation consists of complex future sequences, you have multiple options:

  1. Use stackful coroutines. That is, you can use operator* and get() methods (blocking value acquiring) within a threadpool thread (including the one that runs async 's body). If value is not currently available, these methods temporarily return the thread to threadpool, effeciently allowing it to execute other tasks.
    Note
    Be aware fot std::unique_lock and similar RAII-based lock functions when performing blocking value acquiring operation.
  2. Use stackless coroutines. C++20 introduced coroutines language feature. That is, you can use co_await operator to AFuture value:
    AFuture<int> longOperation();
    AFuture<int> myFunction() {
    int resultOfLongOperation = co_await longOperation();
    return resultOfLongOperation + 1;
    }
  3. Use AComplexFutureOperation. This class creates AFuture (root AFuture) and forwards all exceptions to the root AFuture. This method is not recommended for trivial usecases, as it requires you to extensivly youse onSuccess method in order to get and process AFuture result, leading your code to hardly maintainable spaghetti.
For rare cases, you can default-construct AFuture and the result can be supplied manually with the supplyValue() method:
@code{cpp}
AFuture<int> theFuture;
AThread t([=] {
AThread::sleep(1000); // long operation
theFuture.supplyValue(123);
});
t.start();
cout << *theFuture; // 123
void supplyValue(T v) const noexcept
Pushes the result to AFuture.
Definition: AFuture.h:650
Represents a user-defined thread.
Definition: AThread.h:174
Note
Be aware of exceptions or control flow keywords! If you don't pass the result, AFuture will always stay unavailable, thus all waiting code will wait indefinitely long, leading to resource leaks (CPU and memory). Consider using one of suggested methods of usage instead.

AFuture provides a set of functions for both "value emitting" side: supplyValue(), supplyException(), and "value receiving" side: operator->(), operator*(), get().

When AFuture's operation is completed it calls either onSuccess() or onError(). These callbacks are excepted to be called in any case. Use onFinally() to handle both.

AFuture is a shared_ptr-based wrapper so it can be easily copied, pointing to the same task.

If all AFutures of the task are destroyed, the task is cancelled. If the task is executing when cancel() is called, AFuture waits for the task, however, task's thread is still requested for interrupt. It guarantees that your task cannot be executed or be executing when AFuture destroyed and allows to efficiently utilize c++'s RAII feature.

To manage multiple AFutures, use AAsyncHolder or AFutureSet classes.

Note
AFuture implements work-stealing algorithm to prevent deadlocks and optimizaze thread usage: when waiting for result, AFuture may execute the task (if not default-constructed) on the caller thread instead of waiting. See AFuture::wait for details.

Public Types

using Task = typename super::TaskCallback
 
using Inner = aui::impl::future::CancellationWrapper< typename super::Inner >
 
- Public Types inherited from aui::impl::future::Future< void >
using TaskCallback = std::function< void()>
 
using OnSuccessCallback = typename OnSuccessCallback< void >::type
 

Public Member Functions

 AFuture (T immediateValue)
 
 AFuture (Task task=nullptr) noexcept
 
 AFuture (const AFuture &)=default
 
 AFuture (AFuture &&) noexcept=default
 
AFutureoperator= (const AFuture &)=default
 
AFutureoperator= (AFuture &&) noexcept=default
 
void supplyValue (T v) const noexcept
 Pushes the result to AFuture. More...
 
void supplyException (std::exception_ptr causedBy=std::current_exception()) const noexcept
 Stores an exception from std::current_exception to the future.
 
AFutureoperator= (std::nullptr_t) noexcept
 
bool operator== (const AFuture &r) const noexcept
 
template<aui::invocable< const T & > Callback>
const AFutureonSuccess (Callback &&callback) const noexcept
 Add onSuccess callback to the future. More...
 
template<aui::invocable< const AException & > Callback>
const AFutureonError (Callback &&callback) const noexcept
 Add onError callback to the future. More...
 
template<aui::invocable Callback>
const AFutureonFinally (Callback &&callback) const noexcept
 Adds the callback to both onSuccess and onResult.
 
template<aui::invocable< const T & > Callback>
auto map (Callback &&callback) -> AFuture< decltype(callback(std::declval< T >()))> const
 Maps this AFuture to another type of AFuture.
 
- Public Member Functions inherited from aui::impl::future::Future< void >
 Future (TaskCallback task=nullptr)
 
const _< CancellationWrapper< Inner > > & inner () const noexcept
 
bool isWaitNeeded () const noexcept
 
bool hasResult () const noexcept
 
bool hasValue () const noexcept
 
void reportException () const noexcept
 
void onSuccess (Callback &&callback) const
 
void onError (Callback &&callback) const
 
void onFinally (Callback &&callback) const
 Adds the callback to both onSuccess and onResult.
 
void cancel () const noexcept
 Cancels the AFuture's task. More...
 
void reportInterrupted () const
 
void wait (AFutureWait flags=AFutureWait::DEFAULT) const
 Sleeps if the supplyValue is not currently available. More...
 
FutureReturnType< void >::type get (AFutureWait flags=AFutureWait::DEFAULT) const
 Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available. More...
 
FutureReturnType< void >::type operator* () const
 Returns the task result from the another thread. Sleeps if the task result is not currently available. More...
 
FutureReturnType< void >::type operator* ()
 Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available. More...
 
void * operator-> () const
 Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available. More...
 

Additional Inherited Members

- Static Public Attributes inherited from aui::impl::future::Future< void >
static constexpr bool isVoid
 
- Protected Attributes inherited from aui::impl::future::Future< void >
_< CancellationWrapper< Inner > > mInner
 

Member Function Documentation

◆ onError()

template<typename T = void>
template<aui::invocable< const AException & > Callback>
const AFuture & AFuture< T >::onError ( Callback &&  callback) const
inlinenoexcept

Add onError callback to the future.

The callback will be called on the worker's thread when the async task is returned a result.

onError does not expand AFuture's lifespan, so when AFuture becomes invalid, onSuccess would not be called.

Note
To expand lifespan, create an AAsyncHolder inside your window or object; then put the instance of AFuture there. Example:
...
private:
AAsyncHolder mAsync;
...
mAsync << functionReturningFuture().onSuccess(...); // or onError
Holds a set of futures keeping them valid.
Definition: AAsyncHolder.h:30

◆ onSuccess()

template<typename T = void>
template<aui::invocable< const T & > Callback>
const AFuture & AFuture< T >::onSuccess ( Callback &&  callback) const
inlinenoexcept

Add onSuccess callback to the future.

The callback will be called on the worker's thread when the async task is returned a result.

onSuccess does not expand AFuture's lifespan, so when AFuture becomes invalid, onSuccess would not be called.

Note
To expand lifespan, create an AAsyncHolder inside your window or object; then put the instance of AFuture there. Example:
...
private:
AAsyncHolder mAsync;
...
mAsync << functionReturningFuture().onSuccess(...); // or onError

◆ supplyValue()

template<typename T = void>
void AFuture< T >::supplyValue ( v) const
inlinenoexcept

Pushes the result to AFuture.

Parameters
vvalue

After AFuture grabbed the value, supplyValue calls onSuccess listeners with the new value.

#include <AUI/Thread/AFuture.h>


The documentation for this class was generated from the following file:
Inheritance diagram for AFuture< T >:
Collaboration diagram for AFuture< T >: