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.
I want to implement a thread that can accept function pointers from a main thread and execute them serially. My idea was to use a struct that keeps the function pointer and its object and keep pushing it to a queue. This can be encapsulated in a class. The task thread can then pop from the queue and process it. I also need to synchronize it(so it doesnt block the main thread?), so I was thinking of using a semaphore. Although I have a decent idea of the structure of the program, I am having trouble coding this up, especially the threading and semaphore sync in C++11. It'd be great if someone can suggest an outline by which I can go about implementing this.
EDIT: The duplicate question answers the question about creating a thread pool. It looks like multiple threads are being created to do some work. I only need one thread that can queue function pointers and process them in the order they are received.
Check this code snippet, I have implemented without using a class though. See if it helps a bit. Conditional variable could be avoided here, but I want the reader thread to poll only when there is a signal from the writer so that CPU cycles in the reader won't be wasted.
#include <iostream>
#include <functional>
#include <mutex>
#include <thread>
#include <queue>
#include <chrono>
#include <condition_variable>
using namespace std;
typedef function<void(void)> task_t;
queue<task_t> tasks;
mutex mu;
condition_variable cv;
bool stop = false;
void writer()
{
while(!stop)
{
{
unique_lock<mutex> lock(mu);
task_t task = [](){ this_thread::sleep_for(chrono::milliseconds(100ms)); };
tasks.push(task);
cv.notify_one();
}
this_thread::sleep_for(chrono::milliseconds(500ms)); // writes every 500ms
}
}
void reader()
{
while(!stop)
{
unique_lock<mutex> lock(mu);
cv.wait(lock,[]() { return !stop;});
while( !tasks.empty() )
{
auto task = tasks.front();
tasks.pop();
lock.unlock();
task();
lock.lock();
}
}
}
int main()
{
thread writer_thread([]() { writer();} );
thread reader_thread([]() { reader();} );
this_thread::sleep_for(chrono::seconds(3s)); // main other task
stop = true;
writer_thread.join();
reader_thread.join();
}
Your problem has 2 parts. Storing the list of jobs and manipulating the jobs list in a threadsafe way.
For the first part, look into std::function, std::bind, and std::ref.
For the second part, this is similar to the producer/consumer problem. You can implement a semaphore using std::mutexand std::condition_variable.
There's a hint/outline. Now my full answer...
Step 1)
Store your function pointers in a queue of std::function.
std::queue<std::function<void()>>
Each element in the queue is a function that takes no arguments and returns void.
For functions that take arguments, use std::bind to bind the arguments.
void testfunc(int n);
...
int mynum = 5;
std::function<void()> f = std::bind(testfunction, mynum);
When f is invoked, i.e. f(), 5 will be passed as argument 1 to testfunc. std::bind copies mynum by value immediately.
You probably will want to be able to pass variables by reference as well. This is useful for getting results back from functions as well as passing in shared synchronization devices like semaphores and conditions. Use std::ref, the reference wrapper.
void testfunc2(int& n); // function takes n by ref
...
int a = 5;
std::function<void()> f = std::bind(testfunction, std::ref(a));
std::function and std::bind can work with any callables--functions, functors, or lambdas--which is pretty neat!
Step 2)
A worker thread dequeues while the queue is non-empty. Your code should look similar to the producer/consumer problem.
class AsyncWorker
{
...
public:
// called by main thread
AddJob(std::function<void()> f)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
private:
worker_main()
{
while(!m_exitCondition)
doJob();
}
void doJob()
{
std::function<void()> f;
{
std::unique_lock<std::mutex> lock(m_mutex);
while (m_numJobs == 0)
m_condition.wait(lock);
if (m_exitCondition)
return;
f = std::move(m_queue.front());
m_queue.pop();
--m_numJobs;
}
f();
}
...
Note 1: The synchronization code...with m_mutex, m_condition, and m_numJobs...is essentially what you have to use to implement a semaphore in C++'11. What I did here is more efficient than using a separate semaphore class because only 1 lock is locked. (A semaphore would have its own lock and you would still have to lock the shared queue).
Note 2: You can easily add additional worker threads.
Note 3: m_exitCondition in my example is an std::atomic<bool>
Actually setting up the AddJob function in a polymorphic way gets into C++'11 variadic templates and perfect forwarding...
class AsyncWorker
{
...
public:
// called by main thread
template <typename FUNCTOR, typename... ARGS>
AddJob(FUNCTOR&& functor, ARGS&&... args)
{
std::function<void()> f(std::bind(std::forward<FUNCTOR>(functor), std::forward<ARGS&&>(args)...));
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
I think it may work if you just used pass-by-value instead of using the forwarding references, but I haven't tested this, while I know the perfect forwarding works great. Avoiding perfect forwarding may make the concept slightly less confusing but the code won't be much different...
I want to call a function in parallel in C++, which waits for some time and performs some task. But I don't want the execution flow to wait for the function. I considered using pthread in a simple way but again, I have to wait till it joins back !
void A_Function()
{
/* Call a function which waits for some time and then perform some tasks */
/* Do not wait for the above function to return and continue performing the background tasks */
}
Note: If I do not perform the background tasks while calling the function in parallel then in the next cycle, the function doesn't give me correct output.
Thanks in advance.
Use a std::future to package a std::async task. Wait for the future at the head of your function to ensure that it's completed before the next iteration, since you stated that the next iteration depends on the execution of this background task.
In the example below, I make the background task a simple atomic increment of a counter, and the foreground task just returns the counter value. This is for illustrative purposes only!
#include <iostream>
#include <future>
#include <thread>
class Foo {
public:
Foo() : counter_(0) {}
std::pair<int, std::future<void>> a_function(std::future<void>& f) {
// Ensure that the background task from the previous iteration
// has completed
f.wait();
// Set the task for the next iteration
std::future<void> fut = std::async(std::launch::async,
&Foo::background_task, this);
// Do some work
int value = counter_.load();
// Return the result and the future for the next iteration
return std::make_pair(value, std::move(fut));
}
void background_task() {
++counter_;
}
private:
std::atomic<int> counter_;
};
int main() {
// Bootstrap the procedure with some empty task...
std::future<void> bleak = std::async(std::launch::deferred, [](){});
Foo foo;
// Iterate...
for (size_t i = 0; i < 10; ++i) {
// Call the function
std::pair<int, std::future<void>> result = foo.a_function(bleak);
// Set the future for the next iteration
bleak = std::move(result.second);
// Do something with the result
std::cout << result.first << "\n";
}
}
Live example
I have a program starting an std::thread doing the following: sleep X, execute a function, terminate.
create std::thread(Xms, &func)
wait Xms
then do func()
end
I was wondering if I could for example send a signal to my std::thread in order to instantly break the sleep and do func, then quit.
Do I need to send the signal to std::thread::id in order to perform this?
my thread is launched this way, with a lambda function:
template<typename T, typename U>
void execAfter(T func, U params, const int ms)
{
std::thread thread([=](){
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
func(params);
});
thread.detach();
}
Using wait_for of std::condition_variable would be the way to go, if the thread model can't be changed. In the code snippet below, the use of the condition_variable is wrapped into a class of which objects have to be shared across the threads.
#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
class BlockCondition
{
private:
mutable std::mutex m;
std::atomic<bool> done;
mutable std::condition_variable cv;
public:
BlockCondition()
:
m(),
done(false),
cv()
{
}
void wait_for(int duration_ms)
{
std::unique_lock<std::mutex> l(m);
int ms_waited(0);
while ( !done.load() && ms_waited < duration_ms )
{
auto t_0(std::chrono::high_resolution_clock::now());
cv.wait_for(l, std::chrono::milliseconds(duration_ms - ms_waited));
auto t_1(std::chrono::high_resolution_clock::now());
ms_waited += std::chrono::duration_cast<std::chrono::milliseconds>(t_1 - t_0).count();
}
}
void release()
{
std::lock_guard<std::mutex> l(m);
done.store(true);
cv.notify_one();
}
};
void delayed_func(BlockCondition* block)
{
block->wait_for(1000);
std::cout << "Hello actual work\n";
}
void abortSleepyFunction(BlockCondition* block)
{
block->release();
}
void test_aborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
abortSleepyFunction(&b);
delayed_thread.join();
}
void test_unaborted()
{
BlockCondition b();
std::thread delayed_thread(delayed_func, &b);
delayed_thread.join();
}
int main()
{
test_aborted();
test_unaborted();
}
Note that there might be spurious wakeups that abort the wait call prematurely. To account for that, we count the milliseconds actually waited and continue waiting until the done flag is set.
As was pointed out in the comments, this wasn't the smartest approach for solving your problem in the first place. As implementing a proper interruption mechanism is quite complex and extremely easy to get wrong, here are suggestions for a workaround:
Instead of sleeping for the whole timeout, simply loop over a sleep of fixed small size (e.g. 10 milliseconds) until the desired duration has elapsed. After each sleep you check an atomic flag whether interruption was requested. This is a dirty solution, but is the quickest to pull of.
Alternatively, supply each thread with a condition_variable and do a wait on it instead of doing the this_thread::sleep. Notify the condition variable to indicate the request for interruption. You will probably still want an additional flag to protect against spurious wakeups so you don't accidentally return too early.
Ok, to figure this out I found a new implementation, it's inspired by all your answers so thanks a lot.
First I am gonna do a BombHandler item, in the main Game item. It will have a an attribute containing all the Bomb items.
This BombHandler will be a singleton, containing a timerLoop() function who will execute in a thread (This way I only use ONE thread for xxx bombs, way more effective)
The timerLoop() will usleep(50) then pass through the whole std::list elements and call Bomb::incrTimer() who will increment their internal _timer attribute by 10ms indefinitely, and check bombs who have to explode.
When they reach 2000ms for instance, BombHandler.explode() will be called, exploding the bomb and deleting it.
If another bomb is in range Bomb::touchByFire() will be called, and set the internal attribute of Bomb, _timer, to TIME_TO_EXPLODE (1950ms).
Then it will be explode 50ms later by BombHandler::explode().
Isn't this a nice solution?
Again, thanks for your answers! Hope this can help.
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 function call, while a thread is an execution context. Threads are useful in their own right, but for the purpose 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 value can be retrieved via the member function get(), which effectively synchronizes the program by waiting 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 replacement 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 computation 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 executed concurrently, serially upon get(), or by some other black magic. However, the result is easily obtained 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 callable, 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 separate 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;
}