`std::packaged_task` wraps a function or other callable and connects it to a `std::future`. Calling the task invokes the callable and makes its result available through the future. The task does not choose where it runs: it can be called directly, passed to a `std::thread`, or handed to a task scheduler. section 4.2.2
The template argument is a function signature. In `std::packaged_task<T(Args...)>`, `get_future()` returns `std::future<T>`, and the task’s call operator accepts `Args...`. The wrapped callable’s parameter and return types need not match exactly if the required conversions are possible. section 4.2.2
Run a task on a thread
`std::packaged_task<int(int)> task([](int x) { return x*x; });` creates a task that accepts an `int` and produces an `int`. Get its future with `auto result = task.get_future();`, then run `std::thread worker(std::move(task), 7);`. After `worker.join();`, `result.get()` retrieves the returned value. Moving the task gives the thread the callable while the future remains with the caller. section 4.2.2 section 8.4.1
If the wrapped callable throws, the exception is stored instead of a result; `get()` rethrows it. Destroying an uninvoked task while its future is not ready instead makes the future report a `broken_promise` error. These guarantees cover the task’s result, not every exception-safety obligation around it: code that starts threads must still arrange to join them. section 4.2.4 section 8.4.1
Listing 4.9. Running code on a GUI thread using std::packaged_task
#include <deque>
#include <mutex>
#include <future>
#include <thread>
#include <utility>
std::mutex m;
std::deque<std::packaged_task<void()> > tasks;
bool gui_shutdown_message_received();
void get_and_process_gui_message();
void gui_thread() #1
{
while(!gui_shutdown_message_received()) #2
{
get_and_process_gui_message(); #3
std::packaged_task<void()> task;
{
std::lock_guard<std::mutex> lk(m);
if(tasks.empty()) #4
continue;
task=std::move(tasks.front()); #5
tasks.pop_front();
}
task(); #6
}
}
std::thread gui_bg_thread(gui_thread);
template<typename Func>
std::future<void> post_task_for_gui_thread(Func f)
{
std::packaged_task<void()> task(f); #7
std::future<void> res=task.get_future(); #8
std::lock_guard<std::mutex> lk(m);
tasks.push_back(std::move(task)); #9
return res; #10
}
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":9,\"ch\":48},{\"line\":9,\"ch\":50}],[{\"line\":33,\"ch\":48},{\"line\":33,\"ch\":50}],[{\"line\":11,\"ch\":48},{\"line\":11,\"ch\":50}],[{\"line\":13,\"ch\":48},{\"line\":13,\"ch\":50}],[{\"line\":17,\"ch\":48},{\"line\":17,\"ch\":50}],[{\"line\":19,\"ch\":48},{\"line\":19,\"ch\":50}],[{\"line\":22,\"ch\":48},{\"line\":22,\"ch\":50}],[{\"line\":29,\"ch\":48},{\"line\":29,\"ch\":50}],[{\"line\":30,\"ch\":48},{\"line\":30,\"ch\":50}],[{\"line\":32,\"ch\":48},{\"line\":32,\"ch\":50}],[{\"line\":33,\"ch\":48},{\"line\":33,\"ch\":51}]]"}
!@%STYLE%@!
A GUI thread takes a `std::packaged_task<void()>` from a mutex-protected queue, releases the lock, and invokes the task. The queue handles scheduling; the packaged task handles the connection to its future. section 4.2.2
The same separation helps parallel algorithms: each accumulation block can return its partial result through a `std::future<T>`, which also carries any exception thrown in that block. `std::async` offers another way to associate a future with work; the Concurrency TS version, `std::experimental::packaged_task`, instead produces an experimental future that supports continuations. section 8.4.1 section 4.4.3
