2

A followup with reference to the upcoming feature in C++20 from n3721 "Improvements to std::future and related APIs"

#include <iostream>
#include <future>
#include <exception>

using std::cout;
using std::endl;

int main() {
    auto prom_one = std::promise<std::future<int>>{};
    auto fut_one = prom_one.get_future();

    std::thread{[prom_one = std::move(prom_one)]() mutable {
        auto prom_two = std::promise<int>{};
        auto fut_two = prom_two.get_future();
        prom_two.set_value(1);
        prom_one.set_value(std::move(fut_two));
    }}.detach();

    auto inner_fut_unwrap = fut_one.unwrap();
    auto inner_fut_get = fut_one.get();

    auto th_one = std::thread{[&]() {
        cout << inner_fut_unwrap.get() << endl;
    }};
    auto th_two = std::thread{[&]() {
        cout << inner_fut_get.get() < endl;
    }};

    th_one.join();
    th_two.join();

    return 0;
}

In the code above, which will win the race to print 1? th_one or th_two?


To clarify what race I was talking about, there are two (potential) racy situations here, the latter being the one that is really confusing me.

The first is in the setting and unwrapping of the inner future; the unwrapped future should act as a suitable proxy for the inner future even when the actual set_value has not been called on the inner future. So unwrap() must return a proxy that exposes a thread safe interface regardless of what happens on the other side.

The other situation is what happens to a get() from a future when a proxy for it already exists elsewhere, in this example inner_fut_unwrap is the proxy for inner_fut_get. In such a situation, which should win the race? The unwrapped future or the future fetched via a call to get() on the outer future?

Curious
  • 20,870
  • 8
  • 61
  • 146
  • 1
    `unwrap` is not a thing anymore. Let's not discuss hypothetical features in old papers. – T.C. May 14 '17 at 20:54
  • @T.C. where can I find the latest paper regarding futures? I was under the assumption that http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3857 is the latest one, there seems to be no new one that comes after that here http://www.open-std.org/jtc1/sc22/wg21/docs/papers/ – Curious May 14 '17 at 20:55
  • @T.C. also any idea it was removed? – Curious May 14 '17 at 20:55
  • 2
    It's since made its way into the concurrency TS, which is where you should be looking. As to why, you'll have to ask someone else. – T.C. May 16 '17 at 21:46

1 Answers1

1

This code makes me worried that there is some kind of misunderstanding about what futures and promises are, and what .get() does. It's also a bit weird that we have using namespace std; followed by a lot of std::.

Let's break it down. Here's the important part:

#include <iostream>
#include <future>

int main() {
    auto prom_one = std::promise<std::future<int>>{};
    auto fut_one = prom_one.get_future();
    auto inner_fut_unwrap = fut_one.unwrap();
    auto inner_fut_get = fut_one.get();
    // Boom! throws std::future_error()

So neither thread "wins" the race, since neither thread actually gets a chance to run. Note from the document you linked, for .unwrap(), on p13:

Removes the outer-most future and returns a proxy to the inner future.

So the outer-most future, fut_one, is not valid. When you call .get(), it throws std::future_error1. There is no race.

1: Not guaranteed. Technically undefined behavior.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • What misunderstandings are you hinting at? The first thread serves the purpose of showing that `unwrap()` must work in racy conditions such as when the inner future has not even come into existence and when the inner future has already been set into the outer future. – Curious May 14 '17 at 05:02
  • The second and third threads raise the question about which thread actually gets the value from the shared states of the inner future and the unwrapped future. Both should not get the same value, only one should; `future` does not require the value to be copyable, only movable, unlike `shared_future`. The paper even goes to the length of saying that the value from the inner future will be moved into the outer one. What happens in case of racy situations is not mentioned however, and that is what I was asking in the question – Curious May 14 '17 at 05:02
  • 1
    Sorry, you're right. Next time you might want to put that in the question rather than just posting a big block of code and asking us to figure out what the question is. – Dietrich Epp May 14 '17 at 05:18