How to comprehend "std::future shared state"?
Asked Answered
C

2

6

As per the documentation(http://www.cplusplus.com/reference/future/future/get/), which says that: [emphasis mine]

Once the shared state is ready, the function unblocks and returns (or throws) releasing its shared state. This makes the future object no longer valid: this member function shall be called once at most for every future shared state.

As per the documentation(http://www.cplusplus.com/reference/future/future/), which says that: [emphasis mine]

"Valid" futures are future objects associated to a shared state, and are constructed by calling one of the following functions

async

promise::get_future

packaged_task::get_future

As per the documentation(http://www.cplusplus.com/reference/future/future/get/), which says that: [emphasis mine]

std::future::get

generic template (1) T get(); reference

specialization (2) R& future::get(); // when T is a reference

type (R&) void specialization (3) void future::get(); // when T is void

Return:

value Generally (1), std::move(x), where x is the value stored in the shared state.

For references (2), a reference to the value stored in the shared state.

For void futures (3), nothing.

My question is what is the "std::future shared state"? How can i comprehend "std::future shared state"?

I am a novice in C++.Though I thought and thought about it, but I still can't grasp the idea. I would be very grateful to have some help with this question.

Campos answered 7/6, 2020 at 5:30 Comment(0)
M
3

According to the cppreference documentation on std::future:

When the asynchronous operation is ready to send a result to the creator, it can do so by modifying shared state (e.g. std::promise::set_value) that is linked to the creator's std::future.

Shared state here refers to some mutable stuff readable/writeable by multiple threads. Consider the example straight from the docs:

std::promise<int> p;
std::future<int> f = p.get_future();
std::thread([&p]{ p.set_value_at_thread_exit(9); }).detach();
f.wait();

The main thread and the created thread share p (and since p is stateful, they share state!). Calling std::promise::set_value_at_thread_exit inside the body of the lambda effectively modifies shared state between these two threads. This is essentially all that is meant.

The std::future given by the promise is a representation of the "interesting" part of the shared state -- the value you care about.

Mismate answered 7/6, 2020 at 5:52 Comment(0)
P
1

Scott Meyers has explained this very nicely in the book Effective Modern C++ under Item 38. To quote relevant snippets from the book

... a future is one end of a communications channel through which a callee transmits a result to a caller. The callee (usually running asynchronously) writes the result of its computation into the communications channel (typically via a std::promise object), and the caller reads that result using a future. ... the callee’s result, is stored in ... the shared state. The shared state is typically represented by a heap-based object, but its type, interface, and implementation are not specified by the Standard. Standard Library authors are free to implement shared states in any way they like.

There is also a diagram in the book that nicely shows this.

                             Shared State                                
+----------+ std::future     +-----------+        std::promise  +--------+
|  Caller  |<----------------+  Callee's |<---------------------+ Callee |
+----------+                 |  Result   |          (typically) +--------+
                             +-----------+                                            

Referring to the Shared State spec in the standard we see that, it specifies the expected behavior of the shared state. It details what all functionality should be made available, some how, on the shared state, but doesn't specify any fixed interface. Library implementers can implement it in ways they like. Intuitively it can be thought of as an allocation on the heap that might have to be reference counted and de-allocated when the count reaches zero.

Here are a few bullets to point out important concepts to catch.

  • A callee is an asynchronous function that the caller thread invokes
  • Promise and future are ends of a communication channel between caller and callee
  • The promise is a writer for the shared state while the future is a reader
  • The result generated by the callee cannot be stored in the callee because the callee’s scope may be lost by the time the caller tries to retrieve it
  • The result generated by the callee cannot be stored in the caller because the caller’s future can be copied as shared_futures but result may not be copyable
  • A separate shared state entity is needed to provide an unambiguous unique stable storage location across copies
  • The shared state is implemented in a platform dependent way usually on the heap
  • It typically uses reference counting to track futures and the promise referring to it
  • It is cleaned up when no futures or promise are referring to it
  • It is cleaned up by the thread that releases the last reference

You can read further details in this answer Who is responsible for the shared state of futures and promises and the Standard Specification here

Persse answered 26/7, 2024 at 10:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.