Replacing std::async with own version but where should std::promise live? - c++

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.

Related

Lifetime of promise and set_value_at_thread_exit

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;
}

Why run a packaged_task using an async? [duplicate]

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."

Why do I need to join a thread even if I use std::future::get?

void
set_string(std::promise<std::string>& p)
{
p.set_value("set from thread");
}
int
main()
{
std::promise<std::string> p;
std::future<std::string> f = p.get_future();
std::thread t(&set_string, std::ref(p));
std::cout << f.get() << std::endl;
t.join();
}
Why do I need to call t.join() after I call f.get()? I thought that f.get() will block the main thread until it can get the result and that would mean that the thread has already finished.
Because even after thread finishes execution it is still joinable. You can call detach to allow independend execution. In this case you might want to use set_value_at_thread_exit member of promise to lessen chance that main finishes before thread:
#include <iostream>
#include <string>
#include <thread>
#include <future>
void set_string(std::promise<std::string>& p)
{
p.set_value_at_thread_exit("set from thread");
}
int main()
{
std::promise<std::string> p;
std::future<std::string> f = p.get_future();
std::thread(&set_string, std::ref(p)).detach();
std::cout << f.get() << std::endl;
}
http://coliru.stacked-crooked.com/a/1647ffc41e30e5fb
I believe the rationale for threads is simply that you either explicitly join them or that you explicitly detach them, but if a thread object gets destroyed before either happened, you probably have a problem with your design. The decision was not to assume you want to detach it or join it when the destructor is called, because either one is a bad guess in most situations.
Further, concerning your case, it doesn't matter where the future is set from. The requirements for the thread object are not touched by how it triggers the future, they stay the same.
Note that in your case, since you don't care about the thread any longer, you could simply detach it.

What is the difference between async([](){}) and thread([](){}).detach()?

What is the difference between the two statements below in terms of execution?
async([]() { ... });
thread([]() { ... }).detach();
std::async ([]() { ... }); // (1)
std::thread ([]() { ... }).detach (); // (2)
Most often when std::async is being discussed the first thing noted is that it's broken, the name implies something which doesn't hold when the returned value isn't honored (assigned to a variable to be destructed at the end of the current scope).
In this case the brokenness of std::async is exactly what is going to result in a huge difference between (1) and (2); one will block, the other won't.
Why does std::async block in this context?
The return-value of std::async is a std::future which has a blocking destructor that must execute before the code continues.
In an example as the below g won't execute until f has finished, simply because the unused return value of (3) can't be destroyed until all work is done in the relevant statement.
std::async (f); // (3)
std::async (g); // (4)
What is the purpose of std::thread (...).detach ()?
When detaching from a std::thread we are simply saying; "I don't care about this thread handle anymore, please just execute the damn thing."
To continue with an example similar to the previous one (about std::async) the difference is notably clear; both f and g will execute simultaneously.
std::thread (f).detach ();
std::thread (g).detach ();
I know a good answer was given to your question but if we were to change your question a little something interesting would occur.
Imagine you kept the future returned by the async and didn't detach the thread but instead made a variable for it like this,
Asynchronous code
auto fut=std::async([]() { ... });
std::thread th([]() { ... });
Now you have the setup to what makes these 2 constructs different.
th.join()//you're here until the thread function returns
fut.wait_for(std::chrono::seconds(1)); //wait for 1 sec then continue.
A thread is an all or nothing thing when joining it where as an async can be checked and you can go do other stuff.
wait_for actually returns a status so you can do things like this.
int numOfDots = 0;
//While not ready after waiting 1 sec do some stuff and then check again
while(fut.wait_for(std::chrono::seconds(1)) != std::future_status::ready)
{
(numOfDots++)%=20;
//Print status to the user you're still working on it.
std::cout << "Working on it" <<std::string(numOfDots,'.')<<"\r"<<std::flush();
}
std::cout << "Thanks for waiting!\nHere's your answer: " << fut.get() <<std::endl();
async returns a future object, detach does not. All detach does is allow the execution to continue independently. In order to achieve a similar effect as async, you must use join. For example:
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
{
thread1.join();
thread2.join();
}

What is std::promise?

I'm fairly familiar with C++11's std::thread, std::async and std::future components (e.g. see this answer), which are straight-forward.
However, I cannot quite grasp what std::promise is, what it does and in which situations it is best used. The standard document itself doesn't contain a whole lot of information beyond its class synopsis, and neither does std::thread.
Could someone please give a brief, succinct example of a situation where an std::promise is needed and where it is the most idiomatic solution?
I understand the situation a bit better now (in no small amount due to the answers here!), so I thought I add a little write-up of my own.
There are two distinct, though related, concepts in C++11: Asynchronous computation (a function that is called somewhere else), and concurrent execution (a thread, something that does work concurrently). The two are somewhat orthogonal concepts. Asynchronous computation is just a different flavour of func­tion call, while a thread is an execution context. Threads are useful in their own right, but for the pur­pose of this discussion, I will treat them as an implementation detail.
There is a hierarchy of abstraction for asynchronous computation. For example's sake, suppose we have a function that takes some arguments:
int foo(double, char, bool);
First off, we have the template std::future<T>, which represents a future value of type T. The val­ue can be retrieved via the member function get(), which effectively synchronizes the program by wait­ing for the result. Alternatively, a future supports wait_for(), which can be used to probe whether or not the result is already available. Futures should be thought of as the asynchronous drop-in re­place­ment for ordinary return types. For our example function, we expect a std::future<int>.
Now, on to the hierarchy, from highest to lowest level:
std::async: The most convenient and straight-forward way to perform an asynchronous com­pu­ta­tion is via the async function template, which returns the matching future immediately:
auto fut = std::async(foo, 1.5, 'x', false); // is a std::future<int>
We have very little control over the details. In particular, we don't even know if the function is exe­cu­ted concurrently, serially upon get(), or by some other black magic. However, the result is easily ob­tained when needed:
auto res = fut.get(); // is an int
We can now consider how to implement something like async, but in a fashion that we control. For example, we may insist that the function be executed in a separate thread. We already know that we can provide a separate thread by means of the std::thread class.
The next lower level of abstraction does exactly that: std::packaged_task. This is a template that wraps a function and provides a future for the functions return value, but the object itself is call­able, and calling it is at the user's discretion. We can set it up like this:
std::packaged_task<int(double, char, bool)> tsk(foo);
auto fut = tsk.get_future(); // is a std::future<int>
The future becomes ready once we call the task and the call completes. This is the ideal job for a se­pa­rate thread. We just have to make sure to move the task into the thread:
std::thread thr(std::move(tsk), 1.5, 'x', false);
The thread starts running immediately. We can either detach it, or have join it at the end of the scope, or whenever (e.g. using Anthony Williams's scoped_thread wrapper, which really should be in the standard library). The details of using std::thread don't concern us here, though; just be sure to join or detach thr eventually. What matters is that whenever the function call finishes, our result is ready:
auto res = fut.get(); // as before
Now we're down to the lowest level: How would we implement the packaged task? This is where the std::promise comes in. The promise is the building block for communicating with a future. The principal steps are these:
The calling thread makes a promise.
The calling thread obtains a future from the promise.
The promise, along with function arguments, are moved into a separate thread.
The new thread executes the function and fulfills the promise.
The original thread retrieves the result.
As an example, here's our very own "packaged task":
template <typename> class my_task;
template <typename R, typename ...Args>
class my_task<R(Args...)>
{
std::function<R(Args...)> fn;
std::promise<R> pr; // the promise of the result
public:
template <typename ...Ts>
explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { }
template <typename ...Ts>
void operator()(Ts &&... ts)
{
pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise
}
std::future<R> get_future() { return pr.get_future(); }
// disable copy, default move
};
Usage of this template is essentially the same as that of std::packaged_task. Note that moving the entire task subsumes moving the promise. In more ad-hoc situations, one could also move a promise object explicitly into the new thread and make it a function argument of the thread function, but a task wrapper like the one above seems like a more flexible and less intrusive solution.
Making exceptions
Promises are intimately related to exceptions. The interface of a promise alone is not enough to convey its state completely, so exceptions are thrown whenever an operation on a promise does not make sense. All exceptions are of type std::future_error, which derives from std::logic_error. First off, a description of some constraints:
A default-constructed promise is inactive. Inactive promises can die without consequence.
A promise becomes active when a future is obtained via get_future(). However, only one future may be obtained!
A promise must either be satisfied via set_value() or have an exception set via set_exception() before its lifetime ends if its future is to be consumed. A satisfied promise can die without consequence, and get() becomes available on the future. A promise with an exception will raise the stored exception upon call of get() on the future. If the promise dies with neither value nor exception, calling get() on the future will raise a "broken promise" exception.
Here is a little test series to demonstrate these various exceptional behaviours. First, the harness:
#include <iostream>
#include <future>
#include <exception>
#include <stdexcept>
int test();
int main()
{
try
{
return test();
}
catch (std::future_error const & e)
{
std::cout << "Future error: " << e.what() << " / " << e.code() << std::endl;
}
catch (std::exception const & e)
{
std::cout << "Standard exception: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown exception." << std::endl;
}
}
Now on to the tests.
Case 1: Inactive promise
int test()
{
std::promise<int> pr;
return 0;
}
// fine, no problems
Case 2: Active promise, unused
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
return 0;
}
// fine, no problems; fut.get() would block indefinitely
Case 3: Too many futures
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
auto fut2 = pr.get_future(); // Error: "Future already retrieved"
return 0;
}
Case 4: Satisfied promise
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
}
return fut.get();
}
// Fine, returns "10".
Case 5: Too much satisfaction
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // Error: "Promise already satisfied"
}
return fut.get();
}
The same exception is thrown if there is more than one of either of set_value or set_exception.
Case 6: Exception
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_exception(std::make_exception_ptr(std::runtime_error("Booboo")));
}
return fut.get();
}
// throws the runtime_error exception
Case 7: Broken promise
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
} // Error: "broken promise"
return fut.get();
}
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 promises and associated futures 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.
Bartosz Milewski provides a good writeup.
C++ splits the implementation of futures into a set
of small blocks
std::promise is one of these parts.
A promise is a vehicle for passing the return value (or an
exception) from the thread executing a function to the thread
that cashes in on the function future.
...
A future is the synchronization object constructed around the
receiving end of the promise channel.
So, if you want to use a future, you end up with a promise that you use to get the result of the asynchronous processing.
An example from the page is:
promise<int> intPromise;
future<int> intFuture = intPromise.get_future();
std::thread t(asyncFun, std::move(intPromise));
// do some other stuff
int result = intFuture.get(); // may throw MyException
In a rough approximation you can consider std::promise as the other end of a std::future (this is false, but for illustration you can think as if it was). The consumer end of the communication channel would use a std::future to consume the datum from the shared state, while the producer thread would use a std::promise to write to the shared state.
std::promise is the channel or pathway for information to be returned from the async function. std::future is the synchronization mechanism thats makes the caller wait until the return value carried in the std::promise is ready(meaning its value is set inside the function).
There are really 3 core entities in asynchronous processing. C++11 currently focuses on 2 of them.
The core things you need to run some logic asynchronously are:
The task (logic packaged as some functor object) that will RUN 'somewhere'.
The actual processing node - a thread, a process, etc. that RUNS such functors when they are provided to it. Look at the "Command" design pattern for a good idea of how a basic worker thread pool does this.
The result handle: Somebody needs that result, and needs an object that will GET it for them. For OOP and other reasons, any waiting or synchronization should be done in this handle's APIs.
C++11 calls the things I speak of in (1) std::promise, and those in (3) std::future.
std::thread is the only thing provided publicly for (2). This is unfortunate because real programs need to manage thread & memory resources, and most will want tasks to run on thread pools instead of creating & destroying a thread for every little task (which almost always causes unnecessary performance hits by itself and can easily create resource starvation that is even worse).
According to Herb Sutter and others in the C++11 brain trust, there are tentative plans to add a std::executor that- much like in Java- will be the basis for thread pools and logically similar setups for (2). Maybe we'll see it in C++2014, but my bet is more like C++17 (and God help us if they botch the standard for these).
A std::promise is created as an end point for a promise/future pair and the std::future (created from the std::promise using the get_future() method) is the other end point. This is a simple, one shot method of providing a way for two threads to synchronize as one thread provides data to another thread through a message.
You can think of it as one thread creates a promise to provide data and the other thread collects the promise in the future. This mechanism can only be used once.
The promise/future mechanism is only one direction, from the thread which uses the set_value() method of a std::promise to the thread which uses the get() of a std::future to receive the data. An exception is generated if the get() method of a future is called more than once.
If the thread with the std::promise has not used set_value() to fulfill its promise then when the second thread calls get() of the std::future to collect the promise, the second thread will go into a wait state until the promise is fulfilled by the first thread with the std::promise when it uses the set_value() method to send the data.
With the proposed coroutines of Technical Specification N4663 Programming Languages — C++ Extensions for Coroutines and the Visual Studio 2017 C++ compiler support of co_await, it is also possible to use std::future and std::async to write coroutine functionality. See the discussion and example in https://stackoverflow.com/a/50753040/1466970 which has as one section that discusses the use of std::future with co_await.
The following example code, a simple Visual Studio 2013 Windows console application, shows using a few of the C++11 concurrency classes/templates and other functionality. It illustrates a use for promise/future which works well, autonomous threads which will do some task and stop, and a use where more synchronous behavior is required and due to the need for multiple notifications the promise/future pair does not work.
One note about this example is the delays added in various places. These delays were added only to make sure that the various messages printed to the console using std::cout would be clear and that text from the several threads would not be intermingled.
The first part of the main() is creating three additional threads and using std::promise and std::future to send data between the threads. An interesting point is where the main thread starts up a thread, T2, which will wait for data from the main thread, do something, and then send data to the third thread, T3, which will then do something and send data back to the main thread.
The second part of the main() creates two threads and a set of queues to allow multiple messages from the main thread to each of the two created threads. We can not use std::promise and std::future for this because the promise/future duo are one shot and can not be use repeatedly.
The source for the class Sync_queue is from Stroustrup's The C++ Programming Language: 4th Edition.
// cpp_threads.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <thread> // std::thread is defined here
#include <future> // std::future and std::promise defined here
#include <list> // std::list which we use to build a message queue on.
static std::atomic<int> kount(1); // this variable is used to provide an identifier for each thread started.
//------------------------------------------------
// create a simple queue to let us send notifications to some of our threads.
// a future and promise are one shot type of notifications.
// we use Sync_queue<> to have a queue between a producer thread and a consumer thread.
// this code taken from chapter 42 section 42.3.4
// The C++ Programming Language, 4th Edition by Bjarne Stroustrup
// copyright 2014 by Pearson Education, Inc.
template<typename Ttype>
class Sync_queue {
public:
void put(const Ttype &val);
void get(Ttype &val);
private:
std::mutex mtx; // mutex used to synchronize queue access
std::condition_variable cond; // used for notifications when things are added to queue
std::list <Ttype> q; // list that is used as a message queue
};
template<typename Ttype>
void Sync_queue<Ttype>::put(const Ttype &val) {
std::lock_guard <std::mutex> lck(mtx);
q.push_back(val);
cond.notify_one();
}
template<typename Ttype>
void Sync_queue<Ttype>::get(Ttype &val) {
std::unique_lock<std::mutex> lck(mtx);
cond.wait(lck, [this]{return !q.empty(); });
val = q.front();
q.pop_front();
}
//------------------------------------------------
// thread function that starts up and gets its identifier and then
// waits for a promise to be filled by some other thread.
void func(std::promise<int> &jj) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
std::cout << " func " << myId << " future " << ll << std::endl;
}
// function takes a promise from one thread and creates a value to provide as a promise to another thread.
void func2(std::promise<int> &jj, std::promise<int>&pp) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
auto promiseValue = ll * 100; // create the value to provide as promised to the next thread in the chain
pp.set_value(promiseValue);
std::cout << " func2 " << myId << " promised " << promiseValue << " ll was " << ll << std::endl;
}
// thread function that starts up and waits for a series of notifications for work to do.
void func3(Sync_queue<int> &q, int iBegin, int iEnd, int *pInts) {
int myId = std::atomic_fetch_add(&kount, 1);
int ll;
q.get(ll); // wait on a notification and when we get it, processes it.
while (ll > 0) {
std::cout << " func3 " << myId << " start loop base " << ll << " " << iBegin << " to " << iEnd << std::endl;
for (int i = iBegin; i < iEnd; i++) {
pInts[i] = ll + i;
}
q.get(ll); // we finished this job so now wait for the next one.
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::chrono::milliseconds myDur(1000);
// create our various promise and future objects which we are going to use to synchronise our threads
// create our three threads which are going to do some simple things.
std::cout << "MAIN #1 - create our threads." << std::endl;
// thread T1 is going to wait on a promised int
std::promise<int> intPromiseT1;
std::thread t1(func, std::ref(intPromiseT1));
// thread T2 is going to wait on a promised int and then provide a promised int to thread T3
std::promise<int> intPromiseT2;
std::promise<int> intPromiseT3;
std::thread t2(func2, std::ref(intPromiseT2), std::ref(intPromiseT3));
// thread T3 is going to wait on a promised int and then provide a promised int to thread Main
std::promise<int> intPromiseMain;
std::thread t3(func2, std::ref(intPromiseT3), std::ref(intPromiseMain));
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2 - provide the value for promise #1" << std::endl;
intPromiseT1.set_value(22);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.2 - provide the value for promise #2" << std::endl;
std::this_thread::sleep_for(myDur);
intPromiseT2.set_value(1001);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.4 - set_value 1001 completed." << std::endl;
std::future<int> intFutureMain(intPromiseMain.get_future());
auto t3Promised = intFutureMain.get();
std::cout << "MAIN #2.3 - intFutureMain.get() from T3. " << t3Promised << std::endl;
t1.join();
t2.join();
t3.join();
int iArray[100];
Sync_queue<int> q1; // notification queue for messages to thread t11
Sync_queue<int> q2; // notification queue for messages to thread t12
std::thread t11(func3, std::ref(q1), 0, 5, iArray); // start thread t11 with its queue and section of the array
std::this_thread::sleep_for(myDur);
std::thread t12(func3, std::ref(q2), 10, 15, iArray); // start thread t12 with its queue and section of the array
std::this_thread::sleep_for(myDur);
// send a series of jobs to our threads by sending notification to each thread's queue.
for (int i = 0; i < 5; i++) {
std::cout << "MAIN #11 Loop to do array " << i << std::endl;
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q1.put(i + 100);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q2.put(i + 1000);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
}
// close down the job threads so that we can quit.
q1.put(-1); // indicate we are done with agreed upon out of range data value
q2.put(-1); // indicate we are done with agreed upon out of range data value
t11.join();
t12.join();
return 0;
}
This simple application creates the following output.
MAIN #1 - create our threads.
MAIN #2 - provide the value for promise #1
func 1 future 22
MAIN #2.2 - provide the value for promise #2
func2 2 promised 100100 ll was 1001
func2 3 promised 10010000 ll was 100100
MAIN #2.4 - set_value 1001 completed.
MAIN #2.3 - intFutureMain.get() from T3. 10010000
MAIN #11 Loop to do array 0
func3 4 start loop base 100 0 to 5
func3 5 start loop base 1000 10 to 15
MAIN #11 Loop to do array 1
func3 4 start loop base 101 0 to 5
func3 5 start loop base 1001 10 to 15
MAIN #11 Loop to do array 2
func3 4 start loop base 102 0 to 5
func3 5 start loop base 1002 10 to 15
MAIN #11 Loop to do array 3
func3 4 start loop base 103 0 to 5
func3 5 start loop base 1003 10 to 15
MAIN #11 Loop to do array 4
func3 4 start loop base 104 0 to 5
func3 5 start loop base 1004 10 to 15
The promise is the other end of the wire.
Imagine you need to retrieve the value of a future being computed by an async. However, you don't want it to be computed in the same thread, and you don't even spawn a thread "now" - maybe your software was designed to pick a thread from a pool, so you don't know who will perform che computation in the end.
Now, what do you pass to this (yet unknown) thread/class/entity? You don't pass the future, since this is the result. You want to pass something that is connected to the future and that represents the other end of the wire, so you will just query the future with no knowledge about who will actually compute/write something.
This is the promise. It is a handle connected to your future. If the future is a speaker, and with get() you start listening until some sound comes out, the promise is a microphone; but not just any microphone, it is the microphone connected with a single wire to the speaker you hold. You might know who's at the other end but you don't need to know it - you just give it and wait until the other party says something.
http://www.cplusplus.com/reference/future/promise/
One sentence explanation:
furture::get() waits promse::set_value() forever.
void print_int(std::future<int>& fut) {
int x = fut.get(); // future would wait prom.set_value forever
std::cout << "value: " << x << '\n';
}
int main()
{
std::promise<int> prom; // create promise
std::future<int> fut = prom.get_future(); // engagement with future
std::thread th1(print_int, std::ref(fut)); // send future to new thread
prom.set_value(10); // fulfill promise
// (synchronizes with getting the future)
th1.join();
return 0;
}