What is std::promise?
In the words of [futures.state] a std::future
is an asynchronous return object ("an object that reads results from a shared state") and a std::promise
is an asynchronous provider ("an object that provides a result to a shared state") i.e. a promise is the thing that you set a result on, so that you can get it from the associated future.
The asynchronous provider is what initially creates the shared state that a future refers to. std::promise
is one type of asynchronous provider, std::packaged_task
is another, and the internal detail of std::async
is another. Each of those can create a shared state and give you a std::future
that shares that state, and can make the state ready.
std::async
is a higher-level convenience utility that gives you an asynchronous result object and internally takes care of creating the asynchronous provider and making the shared state ready when the task completes. You could emulate it with a std::packaged_task
(or std::bind
and a std::promise
) and a std::thread
but it's safer and easier to use std::async
.
std::promise
is a bit lower-level, for when you want to pass an asynchronous result to the future, but the code that makes the result ready cannot be wrapped up in a single function suitable for passing to std::async
. For example, you might have an array of several promise
s and associated future
s and have a single thread which does several calculations and sets a result on each promise. async
would only allow you to return a single result, to return several you would need to call async
several times, which might waste resources.
Need help understanding how std::promise and std::future work in this case
Primise/future isn't a value that changes, it is a value that is delivered later.
If you want a value that changes, you can stich together one out of a mutex, condition variable and a bool. However, reasoning about a bool that changes more than once in a multithreaded environment will break most people's brains in my experience.
Better options are things like queues of data guarded by the above, and try pop or try pop all methods that get data off the queue if it is there.
template<class T>
struct threadsafe_queue{
std::optional<T> try_pop();
std::optional<T> wait_and_pop();
bool is_aborted() const;
std::deque<T> pop_all();
void push(T);
void abort();
private:
std::condition_variable cv;
mutable std::mutex m;
std::deque<T> queue;
bool isAborted=false;
std::unique_lock<std::mutex> lock() const;
};
write the above, then send the user input via the queue. The main thread does a try pop and processes if it gets any.
std::optional<T> try_pop(){
auto l=lock();
if (is_aborted()||queue.empty()) return {};
auto r=queue.front();
queue.pop_front();
return r;
}
std::optional<T> wait_and_pop(){
auto l=lock();
cv.wait(l, [&]{return is_aborted()||!queue.empty();});
if (is_aborted()) return {};
auto r=queue.front();
queue.pop_front();
return r;
}
void push(T t){
auto l=lock();
if (is_aborted()) return;
queue.push_back(std::move(t));
cv.notify_one();
}
void abort(){
auto l=lock();
isAborted=true;
cv.notify_all();
}
there are some sample implementations.
Does future in c++ corresponding to promise in javascript?
- Yes.
std::future<T>
stands for a future result ofT
, i.e. the object will at some point in the future hold aT
.std::promise<T>
is an object promising to provide aT
at some point in the future.
Which language got the naming right is debatable.
C++ what are std::shared_future and std::promise
std::shared_future
is when you need to have multiple valid copies of a std::future
, and possibly multiple consumers of said std::future
.
You can move a std::future
into a std::shared_future
.
Consider std::future
:std::shared_future
to be like std::unique_ptr
:std::shared_ptr
.
std::promise
is one way to generate a std::future
.
template<class T>
std::future<std::decay_t<T>> make_ready_future( T&& t ) {
std::promise<std::decay_t<T>> pr;
auto r = pr.get_future();
pr.set_value(std::forward<T>(t));
return r;
}
this is a toy example of std::promise
, where I take a T
and I generate an already-ready std::future<T>
from it.
If you have code that could require threading off, or might already be calculated, you can return a std::future<T>
from it. If it isn't calculated, you return the result of a std::async( ... )
call. If it is already calculated, you return a make_ready_future( calculated value )
.
A slightly more complex situation:
template<class T>
struct promise_pipe {
std::future<T> out;
std::function<void(T)> in;
promise_pipe() {
auto pr = std::make_shared<std::promise<T>>();
out = pr->get_future();
in = [pr](T t)mutable{
if (pr) pr->set_value(std::forward<T>(t));
pr = {};
};
}
};
Here I have written a promise_pipe
.
A promise_pipe<int>
has two fields -- a std::future<int> out
and a std::function<void(int)> in
.
The out
future will be ready if and only if you call in
with an int
.
So you can have a function that returns a std::future<Bitmap>
. You have some network code that is expecting the bitmap to be streamed. So you create a promise_pipe<Bitmap>
, return the std::future<Bitmap>
and store the in
in a "todo" list when the bitmap arrives.
When the bitmap has fully arrived, you just do in(Bitmap)
and whomever is waiting on that future
will be notified.
promise
s are objects designed to allow programmers to generate their own future
s, not just use ones created by the std
library.
Now a packaged_task
is often easier to work with than a std::promise
, and serves much the same purpose as the promise_pipe
above. It is move-only, so you can end up having to wrap it into a std::shared_ptr
and a std::function
anyhow (or a custom move-only std::function
)
Passing std::promise object to a function via direct function call
When you compile this code, even if don't use std::thread
explicitly, you still have to add -pthread
command line option, because internally std::promise
and std::future
depend on the pthread
library.
Without -pthread
on my machine I get:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
With -pthread
:
20*10 = 200
My doubt is if
std::promise
usingstd::thread
then it should throw some compilation or linkage error right?
Very good question. See my answer here.
C++ cannot call set_value for promise move-captured in a lambda?
By default lambda stores all its captured values (non-references) as const
values, you can't modify them. But lambda supports keyword mutable
, you can add it like this:
[/*...*/](/*...*/) mutable { /*...*/ }
This will allow inside body of a lambda to modify all its values.
If for some reason you can't use mutable
, then you can use other work-around:
[/*...*/, p = std::make_shared<ClassName>(std::move(p)), /* ... */](/*...*/) {/*...*/}
In other words wrap your moved value into std::shared_ptr, you can also use std::unique_ptr if you like.
Wrapping into shared pointer solves the problem, because shared pointer (unique also) allows to modify its underlying object value even if pointer itself is const
.
Don't forget inside the body of a lambda to dereference p
as a pointer, in other words if you used p.SomeMethod()
, now you have to use p->SomeMethod()
(with ->
operator).
Lifetime of promise and set_value_at_thread_exit
Why does your code generate problems? Let's start with ansewer to 'when _at_thread_exit
writes to shared state of std::future
and std::promise
?'. It happens after destruction of all thread local variables. Your lambda is called within the thread and after its scope is left, the promise is already destroyed. But what happens when thread calling your lambda has some thread-local variables? Well, the writing will occur after destruction of the std::promise
object. Actually, the rest is really undefined in standard. It seems that passing data to shared state could be done after destruction of std::promise
but information is not really there.
Simplest solution is of course this:
std::promise<int> promise;
auto future = promise.get_future();
const auto task = [](std::promise<int>& promise) {
try {
promise.set_value_at_thread_exit(int_generator_that_can_throw());
} catch (...) {
promise.set_exception_at_thread_exit(std::current_exception());
}
};
std::thread thread(task, std::ref(promise));
// use future
thread.join();
Related Topics
Segmentation Fault When Sending Struct Having Std::Vector Member
Intercepting/Rerouting Tcp Syn Packets to C++ Program in Linux
Hide or Crop Overlapping Text in Qlabel
Range-For-Loops and Std::Vector<Bool>
Is String::C_Str() No Longer Null Terminated in C++11
Std::Fstream Doesn't Create File
While (1) VS. for (;;) Is There a Speed Difference
Find Out If String Ends with Another String in C++
How to Enable C++11 in Qt Creator
Getting Mangled Name from Demangled Name
Read Unicode Utf-8 File into Wstring
Is a Moved-From Vector Always Empty
Returning Temporary Object and Binding to Const Reference
How to Create a Game Loop with Xlib
What Does the Standard Library Guarantee About Self Move Assignment