I'm confusing myself with difference between a future and a promise.
Obviously, they have different methods and stuff, but what is the actual use case?
Is it?:
when I'm managing some async task, I use future to get the value "in future"
when I'm the async task, I use promise as the return type to allow the user get a future from my promise
Future and Promise are the two separate sides of an asynchronous operation.
std::promise is used by the "producer/writer" of the asynchronous operation.
std::future is used by the "consumer/reader" of the asynchronous operation.
The reason it is separated into these two separate "interfaces" is to hide the "write/set" functionality from the "consumer/reader".
auto promise = std::promise<std::string>();
auto producer = std::thread([&]
{
promise.set_value("Hello World");
});
auto future = promise.get_future();
auto consumer = std::thread([&]
{
std::cout << future.get();
});
producer.join();
consumer.join();
One (incomplete) way to implement std::async using std::promise could be:
template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
typedef decltype(func()) result_type;
auto promise = std::promise<result_type>();
auto future = promise.get_future();
std::thread(std::bind([=](std::promise<result_type>& promise)
{
try
{
promise.set_value(func()); // Note: Will not work with std::promise<void>. Needs some meta-template programming which is out of scope for this question.
}
catch(...)
{
promise.set_exception(std::current_exception());
}
}, std::move(promise))).detach();
return std::move(future);
}
Using std::packaged_task which is a helper (i.e. it basically does what we were doing above) around std::promise you could do the following which is more complete and possibly faster:
template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
auto task = std::packaged_task<decltype(func())()>(std::forward<F>(func));
auto future = task.get_future();
std::thread(std::move(task)).detach();
return std::move(future);
}
Note that this is slightly different from std::async where the returned std::future will when destructed actually block until the thread is finished.
Related
We started using the modern C++20 coroutines on our project recently. There is a list of coroutines referred to as Tasks in the Executor, which steps through them one by one resuming them. All of this is done on a single thread. Sometimes coroutines need not to be resumed until some predicate is satisfied. In some cases it may be satisfied by another coroutine, which makes suspending for later execution just fine.
Here are the types in use:
struct Task : std::coroutine_handle<task_promise_t> {
using promise_type = task_promise_t;
};
struct task_promise_t {
Task get_return_object() { return {Task::from_promise(*this)}; }
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
struct Executor {
/* snip */
void enqueue_task(Task &&task) { tasks.push_back(task); }
void tick() {
while (!tasks.empty())
this->step();
}
void step() {
Task task = std::move(tasks.front());
tasks.pop_front();
task.resume();
if (!task.done())
tasks.push_back(task);
}
std::deque<Task> tasks;
/* snip */
}
Example of how I expect it to be used:
auto exec = Executor();
static bool global_predicate = false;
exec.enqueue_task([](Executor* exec) -> Task {
co_await WaitFor(/* bool(void) */ []() -> bool { return global_predicate; });
/* prerequisite satisfied, other logic goes here */
std::cout << "Hello, world" << std::endl;
}(&exec));
exec.step(); // no output, predicate false
exec.step(); // no output, predicate false
global_predicate = true;
exec.step(); // predicate true, "Hello, world!", coroutine is also done
I did manage to get the implementation going, this seems to work fine.
static bool example_global_predicate;
auto coro = []() -> Task {
while (!example_global_predicate)
co_await std::suspend_always();
/* example_global_predicate is now true, do stuff */
co_return;
}();
But I can't a good way to generalize and abstract it into it's own class. How would one go about it? I would expect to see that functionality in the standard library, but seeing how customizable the coroutines are I doubt there is a way to implement a one-size-fits-all solution.
The "await" style of coroutines is intended for doing asynchronous processing in a way that mirrors the synchronous equivalent. In sinchronous code, you might write:
int func(float f)
{
auto value = compute_stuff(f);
auto val2 = compute_more_stuff(value, 23);
return val2 + value;
}
If one or both of these functions is asychronous, you would rewrite it as follows (assuming the presence of appropriate co_await machinery):
task<int> func(float f)
{
auto value = compute_stuff(f);
auto val2 = co_await async_compute_more_stuff(value, 23);
co_return val2 + value;
}
It's structurally the same code except that in one case, func will halt halfway through until async_compute_more_stuff has finished its computation, then be resumed and return its value through Task<int>. The async nature of the code is as implicit as possible; it largely looks like synchronous code.
If you already have some extant async process, and you just want a function to get called when that process concludes, and there is no direct relationship between them, you don't need a coroutine. This code:
static atomic<bool> example_global_predicate;
auto coro = []() -> Task {
while (!example_global_predicate)
co_await std::suspend_always();
/* example_global_predicate is now true, do stuff */
co_return;
}();
Is not meaningfully different from this:
static atomic<bool> example_global_predicate;
register_polling_task([]() -> bool
{
if(!example_global_predicate)
return false;
/* example_global_predicate is now true, do stuff */
return true;
});
register_polling_task represents some global construct which will at regular intervals call your function until it returns true, at which point it assumes that it has done its job and removes the task. Your coroutine version might hide this global construct, but it still needs to be there because somebody has to wake the coroutine up.
Overall, this is not an async circumstance where using coroutines buys you anything in particular.
However, it could still be theoretically useful to attach coroutine resumption to a polling task. The most reasonable way to do this is to put the polling in a task outside of a coroutine. That is, coroutines shouldn't poll for the global state; that's someone else's job.
A coroutine would do something like co_await PollingTask(). This hands the coroutine_handle off to the system that polls the global state. When that global state enters the correct state, it will resume that handle. And when executing the co_await expression, it should also check the state then, so that if the state is already signaled, it should just not halt the coroutine's execution.
PollingTask() would return an awaitable that has all of this machinery built into it.
Suppose we have the following code:
std::promise<int> promise;
auto future = promise.get_future();
const auto task = [](auto 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::move(promise));
// use future
thread.join();
I wonder if this code is correct and safe, and if no, why.
It appears to work fine when compiled with GCC, but crashes (no message is printed) when compiled with MSVC (2017). My guess is that a crash happens because promise local variable inside task goes out of scope and is destroyed too early. If I remove _at_thread_exit suffixes, this code works as expected (or appears to work). It also works correctly when the promise is captured:
const auto task = [p = std::move(promise)]() mutable {
/*...*/
};
Complete compilable example
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();
#include <future>
int main()
{
auto promise = std::make_shared<std::promise<int>>();
auto future = promise->get_future();
const auto task = [](const std::shared_ptr<std::promise<int>>& p)
{
try
{
p->set_value_at_thread_exit(42);
}
catch (...)
{
p->set_exception_at_thread_exit(std::current_exception());
}
};
std::thread thread(task, promise);
// use future
thread.join();
return 0;
}
I want to dispatch a job to the UI thread, then wait for the result and use it from another thread. Like this, but co_await does not work inside the lambda:
dispatcher.RunAsync(CoreDispatcherPriority::Normal, [&]() {
auto res = co_await mStoreContext.RequestPurchaseAsync(L"");
});
Or even waiting for the whole RunAsync operation, if I could get my result out from it
That's because void can not be used as a return value from a coroutine (I can be if you use my my library).
try returning a std::future<void> instead:
dispatcher.RunAsync(CoreDispatcherPriority::Normal, [&]() -> std::future<void> {
auto res = co_await mStoreContext.RequestPurchaseAsync(L"");
});
While working with the threaded model of C++11, I noticed that
std::packaged_task<int(int,int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
task(2,3);
std::cout << f.get() << '\n';
and
auto f = std::async(std::launch::async,
[](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';
seem to do exactly the same thing. I understand that there could be a major difference if I ran std::async with std::launch::deferred, but is there one in this case?
What is the difference between these two approaches, and more importantly, in what use cases should I use one over the other?
Actually the example you just gave shows the differences if you use a rather long function, such as
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Packaged task
A packaged_task won't start on it's own, you have to invoke it:
std::packaged_task<int()> task(sleep);
auto f = task.get_future();
task(); // invoke the function
// You have to wait until task returns. Since task calls sleep
// you will have to wait at least 1 second.
std::cout << "You can see this after 1 second\n";
// However, f.get() will be available, since task has already finished.
std::cout << f.get() << std::endl;
std::async
On the other hand, std::async with launch::async will try to run the task in a different thread:
auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";
// However, the value of the future will be available after sleep has finished
// so f.get() can block up to 1 second.
std::cout << f.get() << "This will be shown after a second!\n";
Drawback
But before you try to use async for everything, keep in mind that the returned future has a special shared state, which demands that future::~future blocks:
std::async(do_work1); // ~future blocks
std::async(do_work2); // ~future blocks
/* output: (assuming that do_work* log their progress)
do_work1() started;
do_work1() stopped;
do_work2() started;
do_work2() stopped;
*/
So if you want real asynchronous you need to keep the returned future, or if you don't care for the result if the circumstances change:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
For more information on this, see Herb Sutter's article async and ~future, which describes the problem, and Scott Meyer's std::futures from std::async aren't special, which describes the insights. Also do note that this behavior was specified in C++14 and up, but also commonly implemented in C++11.
Further differences
By using std::async you cannot run your task on a specific thread anymore, where std::packaged_task can be moved to other threads.
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::thread myThread(std::move(task),2,3);
std::cout << f.get() << "\n";
Also, a packaged_task needs to be invoked before you call f.get(), otherwise you program will freeze as the future will never become ready:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL;DR
Use std::async if you want some things done and don't really care when they're done, and std::packaged_task if you want to wrap up things in order to move them to other threads or call them later. Or, to quote Christian:
In the end a std::packaged_task is just a lower level feature for implementing std::async (which is why it can do more than std::async if used together with other lower level stuff, like std::thread). Simply spoken a std::packaged_task is a std::function linked to a std::future and std::async wraps and calls a std::packaged_task (possibly in a different thread).
TL;DR
std::packaged_task allows us to get the std::future "bounded" to some callable, and then control when and where this callable will be executed without the need of that future object.
std::async enables the first, but not the second. Namely, it allows us to get the future for some callable, but then, we have no control of its execution without that future object.
Practical example
Here is a practical example of a problem that can be solved with std::packaged_task but not with std::async.
Consider you want to implement a thread pool. It consists of a fixed number of worker threads and a shared queue. But shared queue of what? std::packaged_task is quite suitable here.
template <typename T>
class ThreadPool {
public:
using task_type = std::packaged_task<T()>;
std::future<T> enqueue(task_type task) {
// could be passed by reference as well...
// ...or implemented with perfect forwarding
std::future<T> res = task.get_future();
{ std::lock_guard<std::mutex> lock(mutex_);
tasks_.push(std::move(task));
}
cv_.notify_one();
return res;
}
void worker() {
while (true) { // supposed to be run forever for simplicity
task_type task;
{ std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this]{ return !this->tasks_.empty(); });
task = std::move(tasks_.top());
tasks_.pop();
}
task();
}
}
... // constructors, destructor,...
private:
std::vector<std::thread> workers_;
std::queue<task_type> tasks_;
std::mutex mutex_;
std::condition_variable cv_;
};
Such functionality cannot be implemented with std::async. We need to return an std::future from enqueue(). If we called std::async there (even with deferred policy) and return std::future, then we would have no option how to execute the callable in worker(). Note that you cannot create multiple futures for the same shared state (futures are non-copyable).
Packaged Task vs async
p> Packaged task holds a task [function or function object] and future/promise pair. When the task executes a return statement, it causes set_value(..) on the packaged_task's promise.
a> Given Future, promise and package task we can create simple tasks without worrying too much about threads [thread is just something we give to run a task].
However we need to consider how many threads to use or whether a task is best run on the current thread or on another etc.Such descisions can be handled by a thread launcher called async(), that decides whether to create a new a thread or recycle an old one or simply run the task on the current thread. It returns a future .
"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."
"The template function async runs the function f asynchronously
(potentially in a separate thread) and returns a std::future that will
eventually hold the result of that function call."
I'm using vc2011 and it turns out the std::async(std::launch::async, ... ) is a bit buggy (sometimes it does not spawn new threads and runs them in parallel, but instead reuses threads and runs task one after another). This is too slow when I'm doing expensive network calls. So I figured I'd write my own async function. I'm getting stuck though, where should std::promise live? In the 1) thread function, 2) async function, or 3) caller function.
Code:
#include <future>
#include <thread>
#include <iostream>
#include <string>
#include <vector>
std::string thFun() {
throw std::exception("bang!");
return "val";
}
std::future<std::string> myasync(std::promise<std::string>& prms) {
//std::future<std::string> myasync() {
//std::promise<std::string> prms; //needs to outlive thread. How?
std::future<std::string> fut = prms.get_future();
std::thread th([&](){
//std::promise<std::string> prms; //need to return a future before...
try {
std::string val = thFun();
prms.set_value(val);
} catch(...) {
prms.set_exception(std::current_exception());
}
});
th.detach();
return fut;
}
int main() {
std::promise<std::string> prms; //I really want the promise hidden iway in the myasync func and not live here in caller code but the promise needs to outlive myasync and live as long as the thread. How do I do this?
auto fut = myasync(prms);
//auto fut = myasync(); //Exception: future already retrieved
try {
auto res = fut.get();
std::cout << "Result: " << res << std::endl;
} catch(const std::exception& exc) {
std::cout << "Exception: " << exc.what() << std::endl;
}
}
I cant seem to get past the fact that the std::promise needs to outlive the async function (and live as long as the thread), so the promise cant live as a local variable in the async func. But the std::promise shouldn’t live in in the caller code either, as the caller only need to know about futures. And i dont know how to make the promise live in the thread function as async needs to return a future before it even calls the thread func. I’m scratching my head on this one.
Anyone got any ideas?
Edit: I'm highlighting this here as the top comment is a bit misinformed. While the default for std::asycn is allowed to be the dererred mode, when a launch policy of std::launch::async is explicitly set it must behave "as if" threads are spawned and run at once (see wording in en.cppreference.com/w/cpp/thread/async). See the example in pastebin.com/5dWCjjNY for one case where this is not the behavioured seen in vs20011. The solution works great and sped up my real world application by a factor of 10.
Edit 2: MS fixed the bug. More info here: https://connect.microsoft.com/VisualStudio/feedback/details/735731/std-async-std-launch-async-does-not-behave-as-std-thread
Here is one solution:
future<string> myasync()
{
auto prms = make_shared<promise<string>> ();
future<string> fut = prms->get_future();
thread th([=](){
try {
string val = thFun();
// ...
prms->set_value(val);
} catch(...) {
prms->set_exception(current_exception());
}
});
th.detach();
return fut;
}
Allocate promise on the heap, and then pass-by-value [=] a shared_ptr to it through to the lambda.
You need to move the promise into the new thread. Andrew Tomazos's answer does it by creating a std::promise with shared ownership, so that both threads can own the promise, and when the current one returns from the current scope only the new thread owns the promise, i.e. the ownership has been transferred. But std::promise is movable so it should be possible to move it directly into the new thread, except that the "obvious" solution of capturing it doesn't work because lambda's can't capture by move, only by copy (or by reference, which wouldn't work as you'd get a dangling reference.)
However, std::thread supports passing rvalue objects to the new thread's start function. so you can declare the lambda to take a std::promise argument by value, i.e. pass the promise to the lambda rather than capturing it, and then move the promise into one of the arguments of the std::thread e.g
std::future<std::string> myasync() {
std::promise<std::string> prms;
std::future<std::string> fut = prms.get_future();
std::thread th([&](std::promise<std::string> p){
try {
std::string val = thFun();
p.set_value(val);
} catch(...) {
p.set_exception(std::current_exception());
}
}, std::move(prms));
th.detach();
return fut;
}
This move the promise into the std::thread object, which then moves it (in the context of the new thread) into the lambda's parameter p.