C++ what are std::shared_future and std::promise
Asked Answered
P

1

13

I understand what's std::future but i don't understand when and HOW to use std::shared_future and std::promise, and i couldn't find a good explanation online.

I will appreciate some help wrapping my head around it.

By the way the example here isn't really clear http://en.cppreference.com/w/cpp/thread/shared_future

Pigmy answered 27/7, 2017 at 19:40 Comment(4)
Recommendations to find a tutorial or an external explanation are off-topic at Stack Overflow.Saintly
what about helpful example?Pigmy
@AlexanderHuszagh I don't see any request for external resources in this question. I see a statement that OP was not about to find an external resource, but he isn't asking us to provide one.Descend
"The class template std::shared_future provides a mechanism to access the result of asynchronous operations, similar to std::future, except that multiple threads are allowed to wait for the same shared state. Unlike std::future, which is only moveable (so only one instance can refer to any particular asynchronous result), std::shared_future is copyable and multiple shared future objects may refer to the same shared state."Cortezcortical
D
16

std::shared_future is when you need to have multiple valid copies of a std::future, and possibly multiple consumers of said std::future.

You can move a std::future into a std::shared_future.

Consider std::future:std::shared_future to be like std::unique_ptr:std::shared_ptr.


std::promise is one way to generate a std::future.

template<class T>
std::future<std::decay_t<T>> make_ready_future( T&& t ) {
  std::promise<std::decay_t<T>> pr;
  auto r = pr.get_future();
  pr.set_value(std::forward<T>(t));
  return r;
}

this is a toy example of std::promise, where I take a T and I generate an already-ready std::future<T> from it.

If you have code that could require threading off, or might already be calculated, you can return a std::future<T> from it. If it isn't calculated, you return the result of a std::async( ... ) call. If it is already calculated, you return a make_ready_future( calculated value ).

A slightly more complex situation:

template<class T>
struct promise_pipe {
  std::future<T> out;
  std::function<void(T)> in;
  promise_pipe() {
    auto pr = std::make_shared<std::promise<T>>();
    out = pr->get_future();
    in = [pr](T t)mutable{
      if (pr) pr->set_value(std::forward<T>(t));
      pr = {};
    };
  }
};

Here I have written a promise_pipe.

A promise_pipe<int> has two fields -- a std::future<int> out and a std::function<void(int)> in.

The out future will be ready if and only if you call in with an int.

So you can have a function that returns a std::future<Bitmap>. You have some network code that is expecting the bitmap to be streamed. So you create a promise_pipe<Bitmap>, return the std::future<Bitmap> and store the in in a "todo" list when the bitmap arrives.

When the bitmap has fully arrived, you just do in(Bitmap) and whomever is waiting on that future will be notified.


promises are objects designed to allow programmers to generate their own futures, not just use ones created by the std library.

Now a packaged_task is often easier to work with than a std::promise, and serves much the same purpose as the promise_pipe above. It is move-only, so you can end up having to wrap it into a std::shared_ptr and a std::function anyhow (or a custom move-only std::function)

Dressel answered 27/7, 2017 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.