I'm writing some multithreaded code and using promise/future to call a function on a different thread and return its result. For simplicitly, I'll remove the threading part entirely:
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::promise<decltype(f())> promise;
// fulfill the promise
promise.set_value(f());
// block until we have a result
return promise.get_future().get();
}
This works great for any function that returns non-void
. And the return statement getting the future also works for void
. But I can't fulfill the promise if f
is a void
function, because:
promise.set_value(f()); // error: invalid use of void expression
Is there some clever way of setting the value in the void
case in-line, or do I have to just write a helper function like call_set_value(promise, f)
that has an overloads for std::promise<R>
and std::promise<void>
?
A promise is an object that can store a value of type T to be retrieved by a future object (possibly in another thread), offering a synchronization point. On construction, promise objects are associated to a new shared state on which they can store either a value of type T or an exception derived from std::exception .
The answer is using std::future object. Every std::promise object has an associated std::future object, through which others can fetch the value set by promise.
To reuse promises, simply reassign them. it should be my_promise = std::promise<int>() not my_promise = std::my_promise<int>() .
A promise
is only one kind of asynchronous result provider. Instead of a promise
you could use a packaged_task
which wraps a callable object, similar to a std::function
except that invoking it makes the result available via a future
(and of course it handles the difference between void
and non-void results):
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::packaged_task<decltype(f())()> task(std::move(f));
task();
// block until we have a result
return task.get_future().get();
}
N.B. according to the current standard, this code would have a data race if task()
and task.get_future()
happen on separate threads (and so would your original using a promise), so you should call get_future()
before handing the task to the other thread. In practice it should be safe on real implementations and there's a library issue (LWG 2412) to make it valid anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With