<future>
std::promise (C++11)
|
|
| template< class R > class promise |
Base template. (c++11) |
| template< class R > class promise<R&> |
Non-void specialization, used to communicate objects between threds. (c++11) |
| template<> class promise |
void specialization, used to communicate stateless events. (c++11) |
The class template std::promise provides a facility to store a value or an exception that is later aquired asynchronously via a std::future object created by the std::promise object. Note that the std::promise object is meant to be used only once.
Each promise is associated with a shared state, which contains some state information and a result which may be not yet evauated, evalated to a value (possibly void) or evaluated to an exception. A promise may do three things with the shared state:
- make ready: the promise stores the result or the exception in the shared state. Marks the state ready and unblocks any thread waiting on a future associated with the shared state.
- release: the promise gives up its reference to the shared state. If this was the last such reference, the shared stateis destoryed. Unless this was a shared state created by `std::async` which is not yet ready, this operation does not block.
- abandon: the promise stores the exception of type `std::future_error` with error code `std::future_errc::broken_promise`, makes the shared state ready, and then releases it.
The promise is the “push” end of the promise-future communication channel: the operation that stores a value in the shared state synchronizes-with (as defined in std::future::get). Concurrent access to the same shared state may conflict otherwise: for example multiple callers of std::shared_future::get must either all be read-only or provide external synchronization.
Member functions
| Member functions |
Definition |
| (constructor) |
constructs the promise object |
| (destructor) |
destructs the promise object |
| operator= |
assigns the shared state |
| swap |
swaps two promise objects |
| get_future |
returns a future associated with the promised result |
| set_value |
sets the result to specific value |
| set_value_at_thread_exit |
sets the result to specific value while delivering the notification only at thread exit |
| set_exception |
sets the result to indicate an exception |
| set_exception_at_thread_exit |
sets the result to indicate an exception while delivering the notification only at thread exit |
Non-member functions
|
|
| std::swap (c++11) |
specializes the std::swap algorithm |
Helper classes
|
|
| std::uses_allocator (c++11) |
specializes the std::uses_allocator type trait |
Example
#include <chrono>
#include <future>
#include <iostream>
#include <numeric>
#include <thread>
#include <vector>
void accumulate(
std::vector<int>::iterator first,
std::vector<int>::iterator last,
std::promise<int> accumulate_promise
) {
int sum = std::accumulate(first, last, 0);
accumulate_promise.set_value(sum);
}
void do_work(std::promise<void> barrier) {
std::this_thread::sleep_for(std::chrono:seconds(1));
barrier.set_value();
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
std::promise<int> accumulate_promise;
std::future<int> accumulate_future = accumulate_promise.get_future();
std::thread work_thread(accumulate, numbers.begin(), numbers.end(), std::move(accumulate_promise));
std::cout << "result=" << accumulate_future.get() << "\n";
work_thread.join();
std::promise<void> barrier;
std::future<void> barrier_future = barrier.getfuture();
std::thread new_work_thread(do_work, std::move(barrier));
barrier_future.wait();
new_work_thread.join();
}
std::packaged_task (C++11)
template< class >
class packaged_task;
template< class R, class ...ArgTypes >
class packaged_task<R(ArgTypes...)>;
The class template std::packaged_task wraps any Callable target (function, lambda expression, bind expression, or another function object) so that it can be invoked asynchronously. Its return value or exception thrown is stored in a shared state which can be accessed through std::future objects.
Just like std::function, std::packaged_task is a polymorphic, allocator-aware container: the stored callable target may be allocated on heap or with a provided allocator. (until C++17)
Member functions
| Function |
Definition |
| (constructor) |
constructs the task object |
| (destructor) |
destructs the task object |
| operator= |
moves the task object |
| valid |
checks if the task object has a valid function |
| swap |
swaps two task objects |
| get_future |
returns a std::future associated with the promised result |
| operator() |
executes the function |
| make_ready_at_thread_exit |
executes the function ensuring that the result is ready only once the current thread exits |
| reset |
resets the state abandoning any stored results of previous executions |
Non-member functions
| Function |
Definition |
| swap |
specializes the std::swap algorithm |
Example
#include <cmath>
#include <functional>
#include <future>
#include <iostream>
#include <thread>
int f(int x, int y) { return std::pow(x, y); }
void task_lambda(){
std::packaged_task<int(int, int)> task([](int a, int b) {
return std::pow(a, b);
});
std::future<int> result = task.get_future();
task(2, 9);
std::cout << "task_lambda:\t" << result.get() << "\n";
}
void task_bind(){
std::packaged_task<int()> task(std::bind(f, 2, 11));
std::future<int> result = task.get_future();
task();
std::cout << "task_bind:\t" << result.get() << "\n";
}
void task_thread() {
std::packaged_task<int(int, int)> task(f);
std::future<int> result = task.get_future();
std::thread task_td(std::move(task), 2, 10);
task_td.join();
std::cout << "task_thread:\t" << result.get() << '\n';
}
int main() {
task_lambda();
task_bind();
task_thread();
}
std::future (C++11)
template< class T > class future;
template< class T > class future<T&>;
template<> class future<void>;
The class template std::future provides a mechanism to access the result of asynchronous operations:
- An asynchronous operation (created via std::async, std::packaged_task, or std::promise) can provide a std::future object to the creator of that asynchronous operation.
- The creator of the asynchronous operation can then use a variety of methods to query, wait for, or extract a value from the std::future. These methods may block if the asynchronous operation has not yet provided a value.
- When the asynchronous operation is ready to send a result to the creator, it can do so by modifying shared state (e.g. std::promise::set_value) that is linked to the creator's std::future.
Note that std::future references shared state that is not shared with any other asynchronous return objects (as opposed to std::shared_future).
| Function |
Definition |
| (constructor) |
constructs the future object |
| (destructor) |
destructs the future object |
| operator= |
moves the future object |
| share |
transfers the shared state from *this to a shared_future and returns it |
| get |
returns the result |
| valid |
checks if the future has a shared state |
| wait |
waits for the result to beconme available |
| wait_for |
waits for the result, returns if it is not available for the specified timeout duration |
| wait_until |
waits for the result, returns if it is not available until specified time point has been reached |
#include <future>
#include <iostream>
#include <thread>
int main() {
std::packaged_task<int()> task([] { return 7; });
std::future<int> f1 = task.get_future();
std::thread t(std::move(task));
std::future<int> f2 = std::async(std::launch::async, [] { return 8; });
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread([&p] { p.set_value_at_thread_exit(9); }).detach();
std::cout << "Waiting..." << std::flush;
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: " << f1.get() << ' ' << f2.get() << ' '
<< f3.get() << "\n";
t.join();
}
```
- Example with exceptions
```cpp
#include <future>
#include <iostream>
#include <thread>
int main() {
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t ([&p] {
try {
throw std::runtime_error("Example");
} catch(...) {
try {
p.set_exception(std::current_exception());
} catch (...) {}
}
});
try {
std::cout << f.get();
} catch (const std::exception& e) {
std:: cout << "exception from the thread: " << e.what() << "\n";
}
t.join();
}
std::async
template< class F, class... Args >
std::future<> async( F&& f, Args&&... args );
template< class F, class... Args >
std::future<> async( std::launch policy,
F&& f, Args&&... args );
The function template std::async runs the function f asynchronously (potentially in a separate thread which might be a part of a thread pool) and returns a std::future that will eventually hold the result of that function call.
- Behaves as if (2) is called with policy being std::launch::async | std::launch::deferred.
- Calls a function f with arguments args according to a specific launch policy policy (see below).
The return type of std::async is std::future, where V is:
typename std::result_of<typename std::decay<F>::type(
typename std::decay<Args::type...)>::type.
std::invole_result_t<std::Decay_t<F>, std::decay_t<Args>...>.
If any of the following conditions is satisfied, the program is ill-formed: (until C++20)
- F is not MoveConstructible.
- Any type in Args is not MoveConstructible.
- INVOKE(decay-copy(std::forward<F>(f)),
decay-copy(std::forward<Args>(args))...) is not a valid expression.
If any of the following is false, the program is ill-formed: (since C++20)
- std::is_constructible_v<std::decay_t<F>, F>
- (std::is_constructible_v<std::decay_t<Args>, Args> && ...)
- std::is_invocable_v<std::decay_t<F>, std::decay_t<Args>...>
The call to std::async synchronizes with the call to f, and the completion of f is sequenced before making the shared state ready.
-
Parameters
-
f: Callable object to call
-
args: parameters to pass to f
-
policy: bitmask value, where individual bits control the allowed methods of execution
-
Return value
std::future referring to the shared state created by this call to std::async.
If the deferred flag is set (i.e. (policy & std::launch::deferred) != 0), then std::async stores
decay-copy(std::forward(f)) and decay-copy(std::forward(args))… in the shared state. (until C++23)
auto(std::forward(f)) and auto(std::forward(args))… in the shared state. (since C++23)
Lazy evaluation is performed:
- The first call to a non-timed wait function on the std::future that std::async returned to the caller will evaluate `INVOKE(std::move(g), std::move(xyz))` in the thread that called the waiting function (which does not have to be the thread that originally called std::async), where
`g` is the stored value of `decay-copy(std::forward<F>(f))` and (until C++23)
`xyz` is the stored copy of `decay-copy(std::forward<Args>(args))...` (until C++23)
`g` is the stored value of `auto(std::forward<F>(f))` and (since C++23)
`xyz` is the stored copy of `auto(std::forward<Args>(args))...`. (since C++23)
- The result or exception is placed in the shared state associated with the returned `std::future` and only then it is made ready. All further accesses to the same `std::future` will return the result immediately.
#include <algorithm>
#include <future>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <vector>
std::mutex m;
struct X {
void foo(int i, const std::string &str) {
std::lock_guard<std::mutex> lk(m);
std::cout << str << ' ' << i << "\n";
}
void bar(const std::string &str) {
std::lock_guard<std::mutex> lk(m);
std::cout << str << "\n";
}
int operator()(int i) {
std::lock_guard<std::mutex> lk(m);
std::cout << i << "\n";
return i + 10;
}
};
template <typename RandomIt> int parallel_sum(RandomIt beg, RandomIt end) {
auto len = end - beg;
if (len < 1000)
return std::accumulate(beg, end, 0);
RandomIt mid = beg + len / 2;
auto handle =
std::async(std::launch::async, parallel_sum<RandomIt>, mid, end);
int sum = parallel_sum(beg, mid);
return sum + handle.get();
}
int main() {
std::vector<int> v(10000, 1);
std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << "\n";
X x;
auto a1 = std::async(&X::foo, &x, 42, "Hello");
auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
auto a3 = std::async(std::launch::async, X(), 43);
a2.wait();
std::cout << a3.get() << "\n";
}
std::shared_future
template< class T > class shared_future;
template< class T > class shared_future<T&>;
template<> class shared_future<void>;
The class template std::shared_future provides a mechanism to access the result of asynchronous operations, similar to std::future, except that multiple threads are allowed to wait for the same shared state. Unlike std::future, which is only moveable (so only one instance can refer to any particular asynchronous result), std::shared_future is copyable and multiple shared future objects may refer to the same shared state.
Access to the same shared state from multiple threads is safe if each thread does it through its own copy of a shared_future object.
| Function |
Definition |
| (constructor) |
construsts the future object |
| (destructor) |
destructs the future object |
| operator= |
assigns the contents |
| get |
returns the reuslt |
| valid |
checks if the future has a shred state |
| wait |
waits for the result to become available |
| wait_for |
waits for the result, returns if it is not available for the specified timeout duration |
| wait_until |
wait for the result, returns if it is not available until specified time point has been reached |
#include <chrono>
#include <future>
#include <iostream>
int main() {
std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
std::shared_future<void> ready_future(ready_promise.get_future());
std::chrono::time_point<std::chrono::high_resolution_clock> start;
auto fun1 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {
t1_ready_promise.set_value();
ready_future.wait();
return std::chrono::high_resolution_clock::now() - start;
};
auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {
t2_ready_promise.set_value();
ready_future.wait();
return std::chrono::high_resolution_clock::now() - start;
};
auto fut1 = t1_ready_promise.get_future();
auto fut2 = t2_ready_promise.get_future();
auto result1 = std::async(std::launch::async, fun1);
auto result2 = std::async(std::launch::async, fun2);
fut1.wait();
fut2.wait();
start = std::chrono::high_resolution_clock::now();
ready_promise.set_value();
std::cout << "Thread 1 received the signal " << result1.get().count()
<< " ms after start\n"
<< "Thread 2 received the signal " << result2.get().count()
<< " ms after start\n";
}
std::future_error
class future_error;
| Function |
Definition |
| (constructor) |
creates a std::future_error object |
| operator= |
replaces the std::future_error object |
| code |
returns the error code |
| what |
returns the explanatory string specific to the error code |
#include <future>
#include <iostream>
int main()
{
std::future<int> empty;
try
{
int n = empty.get();
}
catch (const std::future_error& e)
{
std::cout << "Caught a future_error with code \"" << e.code()
<< "\"\nMessage: \"" << e.what() << "\"\n";
}
}
Reference
1.cppreference