Futures
Introduction 
Motivation 
Asynchronous Return Object: 
• future<T> 
Asynchronous Provider Objects: 
• async<F, Args…> 
• packaged_task<R, Args…> 
• promise<T> 
Continuation passing style 
Q&A
[C++03, 1.9.6] 
• The observable behavior of the abstract machine is 
its sequence of reads and writes to volatile data and 
calls to library I/O functions. 
 [C++11, 1.10.1]: 
• A thread of execution (also known as a thread) is a 
single flow of control within a program... The 
execution of the entire program consists of an 
execution of all of its threads...
 [C++11, 30.1.1]: 
• The following subclauses describe components 
to create and manage threads (1.10), perform 
mutual exclusion, and communicate 
conditions and values between threads… 
Subclause Header 
Threads <thread> 
Mutual exclusion <mutex> 
Condition variables <condition_variable> 
Futures <future>
Having independent time consuming tasks: 
// ... 
device target_device; 
target_device.initialize(); // <- time consuming 
configuration_storage db; 
configuration config; 
db.load(config); // <- time consuming 
target_device.configure(config);
Execute time consuming tasks 
simultaneously, naive approach: 
// ... 
configuration_storage db; 
configuration config; 
thread loader([&db, &config]{ db.load(config); }); 
// <- run loading config in a separate thread 
device target_device; 
target_device.initialize(); 
// <- continue device initialization in current thread 
loader.join(); 
// <- assume loading done at this point 
target_device.configure(config);
Execute time consuming tasks 
simultaneously, thread pool approach: 
class async_exec_service { 
public: 
void exec(function<void()> f); 
}; 
// ... 
async_exec_service exec_service; 
// ... 
configuration_storage db; 
configuration config; 
exec_service.exec([&db, &config]{ db.load(config); }); 
// <- run loading config in the thread pool 
device target_device; 
target_device.initialize(); 
// <- continue device initialization in current thread 
// hmmm... are we ready for proceed ??? 
target_device.configure(config);
 Execute time consuming tasks simultaneously, thread 
pool approach with synchronization: 
class async_exec_service { public: void exec(function<void()> f); }; 
// ... 
async_exec_service exec_service; 
// ... 
configuration_storage db; 
unique_ptr<configuration> config; 
mutex config_guard; 
condition_variable config_cv; 
exec_service.exec([&]{ 
unique_lock<mutex> lock(config_guard); 
config.reset(new configuration); 
db.load(*config); 
config_cv.notify_one(); 
}); // <- run loading config in the thread pool 
device target_device; 
target_device.initialize(); // continue device initialization in current thread 
{ // wait for configuration loading done 
unique_lock<mutex> lock(config_guard); 
config_cv.wait(lock, [&]{ return (config != nullptr); }); 
} 
// we are ready for proceed 
target_device.configure(*config);
The Standard Library provides a unified 
solution communicate data between 
threads: 
• shared state object – privately held object with a 
placeholder for result and some auxiliary data; 
• asynchronous return object – reads result from 
a shared state; 
• asynchronous provider - provides shared state 
object with a value.
SharedState – internal shared state; 
future – asynchronous return object; 
Setter – asynchronous provider object: 
• async 
• packaged_task 
• promise
 Execute time consuming tasks simultaneously, using 
future<T>: 
class async_exec_service { 
public: 
template <typename _Function> 
auto exec(_Function&& f) -> future<decltype(f())> 
{ /*...*/ } 
}; 
async_exec_service exec_service; 
// ... 
configuration_storage db; 
future<configuration> config = exec_service.exec([&db]{ 
configuration config; 
db.load(config); 
return config; 
}); 
device target_device; 
target_device.initialize(); 
target_device.configure(config.get()); 
// wait for result and proceed
valid() – tests if the future has a shared 
state; 
get() – retrieves value, wait if needed; 
wait()/wait_for(delay)/wait_until(time) – 
waits the future to be populated with result; 
share() – makes shared_future from this 
future; invalidates this future object.
shares its shared state object between 
several asynchronous return objects: 
the main purpose – signal the result is 
ready to multiple waiting threads
Runs a function in a separate thread and 
set its result to future: 
• step back to naive approach: 
configuration_storage db; 
future<configuration> config = async([&db]{ 
configuration config; 
db.load(config); 
return config; 
}); // run loading config in a separate thread 
device target_device; 
target_device.initialize(); 
// continue device initialization in current thread 
target_device.configure(config.get());
template< class Function, class... Args> 
result_type async(Function&& f, Args&&... args); 
template< class Function, class... Args > 
result_type async(launch policy, Function&& f, Args&&... args); 
async launch policy: 
 launch::async – launch a new thread for execution; 
 launch::deferred – defers the execution until the 
returned future value accessed; performs execution in 
current thread; 
 launch::async|launch::deferred – used by default, 
allows the implementation to choose one.
configuration_storage db; 
future<configuration> config = async([&db]{ 
configuration config; 
db.load(config); 
return config; 
}); // run loading config in a separate thread 
device target_device; 
if (!target_device.initialize()) { 
return; // what will happen to config here ??? 
} 
target_device.configure(config.get()); 
 [3.6.8/5]: 
• … If the implementation chooses the launch::async policy, 
- a call to a waiting function on an asynchronous return object that shares 
the shared state created by this async call shall block until the 
associated thread has completed, as if joined; 
…
 provides better control over execution; 
 does not execute threads itself; 
 provides a wrapper on a function or a callable object for 
store returned value/exception in a future. 
configuration_storage db; 
packaged_task<configuration ()> load_config([&db] { 
configuration config; 
db.load(config); 
return config; 
}); 
future<configuration> config = load_config.get_future(); 
// just get future<> for future :) 
load_config(); // loading config goes here 
device target_device; 
target_device.initialize(); 
target_device.configure(config.get());
 Implementation for async_exec_service: 
class async_exec_service { 
queue<function<void ()>> _exec_queue; 
// worker threads will take functions from _exec_queue 
// ... 
void enqueue(function<void ()> task) {/* put task to _exec_queue */} 
public: 
template <typename _Function> 
auto exec(_Function&& f) -> future<decltype(f())> 
{ 
typedef decltype(f()) _Result; 
shared_ptr<packaged_task<_Result()>> task = 
make_shared<packaged_task<_Result()>>(f); 
function<void()> task_wrapper = [task]{(*task)();}; 
enqueue(task_wrapper); 
return task->get_future(); 
} 
// ... 
};
 provides the highest level of control over the shared 
state; 
 does not require a function or callable object for populate 
shared state; 
 requires executing thread explicitly set value/exception to 
shared state.
 Yet another implementation for async_exec_service: 
class async_exec_service { 
queue<function<void ()>> _exec_queue; 
// worker threads will take functions from _exec_queue 
// ... 
void enqueue(function<void ()> task) {/* put task to _exec_queue */} 
public: 
template <typename _Function> 
auto exec(_Function&& f) -> future<decltype(f())> 
{ 
typedef decltype(f()) _Result; 
shared_ptr<promise<_Result>> result = 
make_shared<promise<_Result>>(); 
function<void()> task_wrapper = [result, f]{ 
try { 
result->set_value(f()); 
} catch (...) { 
result->set_exception(current_exception()); 
} 
} 
enqueue(task_wrapper); 
return result->get_future(); 
} 
};
. || …
Currently is not a part of C++ Standard 
Going to be included in C++17 (N3857) 
Already available in boost
 compose two futures by declaring one to be the 
continuation of another: 
device target_device; 
configuration_storage db; 
future<void> configure = async([&db]{ 
configuration config; 
db.load(config); 
return config; 
}).then([&target_device](future<configuration> config){ 
// JUST FOR EXAMPLE: 
// config is ready at this point, 
// but it doesn’t mean we could already configure the device 
}); 
target_device.initialize();
 wait a number of futures for at least one to be 
ready: 
device target_device; 
configuration_storage db; 
configuration config; 
future<bool> tasks[] = { 
async([&target_device]{ return target_device.initialize(); }), 
async([&db, &config]{ db.load(config); return true; }), 
}; 
future<vector<future<bool>>> anyone = when_any(begin(tasks), end(tasks)); 
future<bool> anyone_completed = anyone.then( 
[](future<vector<future<bool>>> lst) { 
// JUST FOR EXAMPLE 
for (future<bool>& f: lst) { 
if (f.is_ready()) 
return f.get(); // won't block here 
} 
});
 wait for a number of futures to be ready: 
device target_device; 
configuration_storage db; 
future<bool> init_device = async([&target_device]{ 
return target_device.initialize(); 
}); 
future<configuration> load_config = async([&db]{ 
configuration config; 
db.load(config); 
return config; 
}); 
future<tuple<future<bool>, future<configuration>>> init_all = 
when_all(init_device, load_config); 
future<bool> device_ready = init_all.then( 
[&target_device](tuple<future<bool>, future<configuration>> params){ 
bool hw_ok = get<0>().get(); 
if (!hw_ok) return false; 
configuration config = get<1>().get(); 
target_device.configure(config); 
return true; 
} 
);
Thank You!

C++11 Multithreading - Futures

  • 1.
  • 2.
    Introduction Motivation AsynchronousReturn Object: • future<T> Asynchronous Provider Objects: • async<F, Args…> • packaged_task<R, Args…> • promise<T> Continuation passing style Q&A
  • 3.
    [C++03, 1.9.6] •The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.  [C++11, 1.10.1]: • A thread of execution (also known as a thread) is a single flow of control within a program... The execution of the entire program consists of an execution of all of its threads...
  • 4.
     [C++11, 30.1.1]: • The following subclauses describe components to create and manage threads (1.10), perform mutual exclusion, and communicate conditions and values between threads… Subclause Header Threads <thread> Mutual exclusion <mutex> Condition variables <condition_variable> Futures <future>
  • 5.
    Having independent timeconsuming tasks: // ... device target_device; target_device.initialize(); // <- time consuming configuration_storage db; configuration config; db.load(config); // <- time consuming target_device.configure(config);
  • 6.
    Execute time consumingtasks simultaneously, naive approach: // ... configuration_storage db; configuration config; thread loader([&db, &config]{ db.load(config); }); // <- run loading config in a separate thread device target_device; target_device.initialize(); // <- continue device initialization in current thread loader.join(); // <- assume loading done at this point target_device.configure(config);
  • 7.
    Execute time consumingtasks simultaneously, thread pool approach: class async_exec_service { public: void exec(function<void()> f); }; // ... async_exec_service exec_service; // ... configuration_storage db; configuration config; exec_service.exec([&db, &config]{ db.load(config); }); // <- run loading config in the thread pool device target_device; target_device.initialize(); // <- continue device initialization in current thread // hmmm... are we ready for proceed ??? target_device.configure(config);
  • 8.
     Execute timeconsuming tasks simultaneously, thread pool approach with synchronization: class async_exec_service { public: void exec(function<void()> f); }; // ... async_exec_service exec_service; // ... configuration_storage db; unique_ptr<configuration> config; mutex config_guard; condition_variable config_cv; exec_service.exec([&]{ unique_lock<mutex> lock(config_guard); config.reset(new configuration); db.load(*config); config_cv.notify_one(); }); // <- run loading config in the thread pool device target_device; target_device.initialize(); // continue device initialization in current thread { // wait for configuration loading done unique_lock<mutex> lock(config_guard); config_cv.wait(lock, [&]{ return (config != nullptr); }); } // we are ready for proceed target_device.configure(*config);
  • 9.
    The Standard Libraryprovides a unified solution communicate data between threads: • shared state object – privately held object with a placeholder for result and some auxiliary data; • asynchronous return object – reads result from a shared state; • asynchronous provider - provides shared state object with a value.
  • 10.
    SharedState – internalshared state; future – asynchronous return object; Setter – asynchronous provider object: • async • packaged_task • promise
  • 11.
     Execute timeconsuming tasks simultaneously, using future<T>: class async_exec_service { public: template <typename _Function> auto exec(_Function&& f) -> future<decltype(f())> { /*...*/ } }; async_exec_service exec_service; // ... configuration_storage db; future<configuration> config = exec_service.exec([&db]{ configuration config; db.load(config); return config; }); device target_device; target_device.initialize(); target_device.configure(config.get()); // wait for result and proceed
  • 12.
    valid() – testsif the future has a shared state; get() – retrieves value, wait if needed; wait()/wait_for(delay)/wait_until(time) – waits the future to be populated with result; share() – makes shared_future from this future; invalidates this future object.
  • 13.
    shares its sharedstate object between several asynchronous return objects: the main purpose – signal the result is ready to multiple waiting threads
  • 14.
    Runs a functionin a separate thread and set its result to future: • step back to naive approach: configuration_storage db; future<configuration> config = async([&db]{ configuration config; db.load(config); return config; }); // run loading config in a separate thread device target_device; target_device.initialize(); // continue device initialization in current thread target_device.configure(config.get());
  • 15.
    template< class Function,class... Args> result_type async(Function&& f, Args&&... args); template< class Function, class... Args > result_type async(launch policy, Function&& f, Args&&... args); async launch policy:  launch::async – launch a new thread for execution;  launch::deferred – defers the execution until the returned future value accessed; performs execution in current thread;  launch::async|launch::deferred – used by default, allows the implementation to choose one.
  • 16.
    configuration_storage db; future<configuration>config = async([&db]{ configuration config; db.load(config); return config; }); // run loading config in a separate thread device target_device; if (!target_device.initialize()) { return; // what will happen to config here ??? } target_device.configure(config.get());  [3.6.8/5]: • … If the implementation chooses the launch::async policy, - a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; …
  • 17.
     provides bettercontrol over execution;  does not execute threads itself;  provides a wrapper on a function or a callable object for store returned value/exception in a future. configuration_storage db; packaged_task<configuration ()> load_config([&db] { configuration config; db.load(config); return config; }); future<configuration> config = load_config.get_future(); // just get future<> for future :) load_config(); // loading config goes here device target_device; target_device.initialize(); target_device.configure(config.get());
  • 18.
     Implementation forasync_exec_service: class async_exec_service { queue<function<void ()>> _exec_queue; // worker threads will take functions from _exec_queue // ... void enqueue(function<void ()> task) {/* put task to _exec_queue */} public: template <typename _Function> auto exec(_Function&& f) -> future<decltype(f())> { typedef decltype(f()) _Result; shared_ptr<packaged_task<_Result()>> task = make_shared<packaged_task<_Result()>>(f); function<void()> task_wrapper = [task]{(*task)();}; enqueue(task_wrapper); return task->get_future(); } // ... };
  • 19.
     provides thehighest level of control over the shared state;  does not require a function or callable object for populate shared state;  requires executing thread explicitly set value/exception to shared state.
  • 20.
     Yet anotherimplementation for async_exec_service: class async_exec_service { queue<function<void ()>> _exec_queue; // worker threads will take functions from _exec_queue // ... void enqueue(function<void ()> task) {/* put task to _exec_queue */} public: template <typename _Function> auto exec(_Function&& f) -> future<decltype(f())> { typedef decltype(f()) _Result; shared_ptr<promise<_Result>> result = make_shared<promise<_Result>>(); function<void()> task_wrapper = [result, f]{ try { result->set_value(f()); } catch (...) { result->set_exception(current_exception()); } } enqueue(task_wrapper); return result->get_future(); } };
  • 21.
  • 22.
    Currently is nota part of C++ Standard Going to be included in C++17 (N3857) Already available in boost
  • 23.
     compose twofutures by declaring one to be the continuation of another: device target_device; configuration_storage db; future<void> configure = async([&db]{ configuration config; db.load(config); return config; }).then([&target_device](future<configuration> config){ // JUST FOR EXAMPLE: // config is ready at this point, // but it doesn’t mean we could already configure the device }); target_device.initialize();
  • 24.
     wait anumber of futures for at least one to be ready: device target_device; configuration_storage db; configuration config; future<bool> tasks[] = { async([&target_device]{ return target_device.initialize(); }), async([&db, &config]{ db.load(config); return true; }), }; future<vector<future<bool>>> anyone = when_any(begin(tasks), end(tasks)); future<bool> anyone_completed = anyone.then( [](future<vector<future<bool>>> lst) { // JUST FOR EXAMPLE for (future<bool>& f: lst) { if (f.is_ready()) return f.get(); // won't block here } });
  • 25.
     wait fora number of futures to be ready: device target_device; configuration_storage db; future<bool> init_device = async([&target_device]{ return target_device.initialize(); }); future<configuration> load_config = async([&db]{ configuration config; db.load(config); return config; }); future<tuple<future<bool>, future<configuration>>> init_all = when_all(init_device, load_config); future<bool> device_ready = init_all.then( [&target_device](tuple<future<bool>, future<configuration>> params){ bool hw_ok = get<0>().get(); if (!hw_ok) return false; configuration config = get<1>().get(); target_device.configure(config); return true; } );
  • 26.