liveBook · Manning

Std::shared_future

As explained in C++ Concurrency in Action, Second Edition

A C++ Concurrency TS class template representing an asynchronous result accessible by multiple consumers.

Use std::shared_future<T> when several consumers need the same one-off asynchronous result. Unlike the move-only std::future<T>, a shared future is copyable: each copy refers to the same associated state, becomes ready at the same time, and can access its result. Use std::shared_future<void> when the event carries no value. section 4.2 section 4.2.5

Turn a unique future into a shared future

A promise's get_future() supplies a std::future<int>. Moving that future into std::shared_future<int> transfers the reference to the result: the original future becomes invalid, while the shared future is valid. Alternatively, call share() on a future; each consumer can then receive a copy. section 4.2.5

std::promise<int> p;
std::future<int> f(p.get_future());
assert(f.valid());                            #1
std::shared_future<int> sf(std::move(f));
assert(!f.valid());                           #2
assert(sf.valid());                           #3

The validity checks make the ownership transfer visible. section 4.2.5

Copy the shared future for each thread rather than accessing one shared_future object concurrently. Access to an individual future object is not synchronized; unprotected concurrent access can cause a data race. Separate copies safely access their common asynchronous state through library synchronization. section 4.2.5

One result, several dependencies

In a parallel spreadsheet, one cell's final value may feed several formulas. Each dependent task can hold its own shared_future for that value and wait if the cell is not ready, while unrelated tasks proceed. section 4.2.5

The separate Concurrency TS type std::experimental::shared_future also supports multiple continuations on one result. Each continuation receives an experimental shared future; its return value is an experimental future unless shared again. section 4.4.4

auto fut=spawn_async(some_function).share();
auto fut2=fut.then([](std::experimental::shared_future<some_data> data){
    do_stuff(data);
    });
auto fut3=fut.then([](std::experimental::shared_future<some_data> data){
    return do_other_stuff(data);
    });

Two continuations attach to the same experimental shared future. section 4.4.4

How C++ Concurrency in Action, Second Edition covers it

How deep it goes
Explains copyability, conversion from std::future, and object-versus-state synchronization without attempting an exhaustive API reference.
Examples
Shows a promise-derived future becoming shared, parallel spreadsheet dependencies, and two continuations attached to one result.
What it assumes
Builds on std::future and std::promise while explaining unique versus shared ownership and why separate objects matter.
What you can do after
Apply it via std::shared_future to distribute one result across threads without concurrently accessing an unprotected future object.
How it connects
Connects std::future, std::promise, asynchronous shared state, data races, and continuations.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C++ Concurrency in Action, Second Edition. The section links point to the parts of the book it draws on.